Skip to content

Conversation

oscartbeaumont
Copy link
Member

@oscartbeaumont oscartbeaumont commented Sep 24, 2025

Summary by CodeRabbit

  • New Features

    • Added Devtools controls to simulate Pro status in development: quickly promote or demote the current user to/from Pro to test Pro-only experiences without real billing.
    • Pro simulation updates user subscription state to reflect active or cleared status for realistic UI/feature testing.
  • Chores

    • Restricted these controls to development environments to prevent accidental use in production.

Copy link
Contributor

vercel bot commented Sep 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
cap-web Ready Ready Preview Comment Sep 24, 2025 7:24am

Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adds two server actions to toggle a user’s Pro status in development and exposes them via two forms in the CapDevtools UI. Actions validate development environment, require an active session, and update Stripe-related fields for the current user in the database.

Changes

Cohort / File(s) Summary
Devtools server actions
apps/web/app/Layout/devtoolsServer.ts
Introduces promoteToPro and demoteFromPro server-only actions; guard on NODE_ENV !== 'development'; fetch current user; update user’s Stripe fields (development/active vs null); persist via drizzle-orm.
Devtools UI integration
apps/web/app/Layout/providers.tsx
Imports server actions and adds two forms within CapDevtools to trigger promote/demote of Pro status; existing UI otherwise unchanged.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer (browser)
  participant UI as CapDevtools UI
  participant SA as Server Action (promoteToPro/demoteFromPro)
  participant Auth as getCurrentUser
  participant DB as DB (users)

  Dev->>UI: Click "Promote" or "Demote"
  UI->>SA: Submit form (server action)
  SA->>SA: Check NODE_ENV === "development"
  SA->>Auth: getCurrentUser()
  Auth-->>SA: user | null
  alt user present
    SA->>DB: update users set stripe* = {active/dev or null} where id = user.id
    DB-->>SA: ok
    SA-->>UI: success (no payload)
    UI-->>Dev: UI reflects devtools action completion
  else no session
    SA-->>UI: error (no session)
    UI-->>Dev: show error
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

I nudge a toggle, hop and go,
From plain to Pro, then back to slow.
In dev burrows, flags take flight—
Stripe fields dance in sandbox light.
Thump-thump logs, a happy tune,
Carrots earned, we’ll ship by noon. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "devtools: toggle for Cap Pro" is concise, scoped, and directly reflects the main change in the PR—adding a devtools UI toggle and server functions to promote/demote Cap Pro; it avoids vague wording and is specific enough that a reviewer scanning history will understand the primary intent.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cap-pro-button

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 and usage tips.

@oscartbeaumont oscartbeaumont marked this pull request as ready for review September 24, 2025 07:13
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
apps/web/app/Layout/providers.tsx (2)

74-74: Rename module to kebab-case and update import path

Follow repo convention: use kebab-case for TS/JS module filenames.

Apply this diff after renaming devtoolsServer.tsdevtools-server.ts:

-import { demoteFromPro, promoteToPro } from "./devtoolsServer";
+import { demoteFromPro, promoteToPro } from "./devtools-server";

Please confirm the file was renamed on disk and any other imports were updated.


126-149: Prefer useEffectMutation over plain form actions and perform targeted cache updates

Align with client guidelines: use useEffectMutation to call Server Actions and update caches (e.g., current-user) via setQueryData/setQueriesData or refresh affected UI.

Apply this diff to replace forms with buttons invoking mutations:

-        <div className="flex items-center space-x-2">
-          <form action={promoteToPro}>
-            <button
-              type="submit"
-              className="rounded bg-green-600 px-2 py-1 text-xs font-medium text-white hover:bg-green-700"
-            >
-              Promote to Pro
-            </button>
-          </form>
-          <form action={demoteFromPro}>
-            <button
-              type="submit"
-              className="rounded bg-red-600 px-2 py-1 text-xs font-medium text-white hover:bg-red-700"
-            >
-              Demote from Pro
-            </button>
-          </form>
-        </div>
+        <div className="flex items-center space-x-2">
+          <button
+            type="button"
+            className="rounded bg-green-600 px-2 py-1 text-xs font-medium text-white hover:bg-green-700 disabled:opacity-50"
+            onClick={() => promote.mutate()}
+            disabled={promote.isPending}
+          >
+            Promote to Pro
+          </button>
+          <button
+            type="button"
+            className="rounded bg-red-600 px-2 py-1 text-xs font-medium text-white hover:bg-red-700 disabled:opacity-50"
+            onClick={() => demote.mutate()}
+            disabled={demote.isPending}
+          >
+            Demote from Pro
+          </button>
+        </div>

Add these supporting changes outside the selected range:

// imports
import { useEffectMutation } from "@/lib/EffectRuntime";
import { useQueryClient } from "@tanstack/react-query";
import { useRouter } from "next/navigation";

Inside CapDevtools(), before return:

const qc = useQueryClient();
const router = useRouter();

const promote = useEffectMutation(promoteToPro, {
  onSuccess: () => {
    // Prefer targeted cache updates. Adjust queryKey to your actual current-user key.
    qc.setQueriesData({ queryKey: ["current-user"] }, (u: any) =>
      u ? { ...u, stripeCustomerId: "development", stripeSubscriptionId: "development", stripeSubscriptionStatus: "active" } : u,
    );
    router.refresh(); // optional, if parts of UI rely on RSC data
  },
});

const demote = useEffectMutation(demoteFromPro, {
  onSuccess: () => {
    qc.setQueriesData({ queryKey: ["current-user"] }, (u: any) =>
      u ? { ...u, stripeCustomerId: null, stripeSubscriptionId: null, stripeSubscriptionStatus: null } : u,
    );
    router.refresh(); // optional
  },
});
  • Replace ["current-user"] with the real query key used for the signed-in user in this app.
  • If the app doesn’t cache the user with TanStack Query, keep router.refresh() to update RSC-derived UI.
apps/web/app/Layout/devtoolsServer.ts (4)

9-10: Remove redundant "use server" inside a server-only module

The file is already server-only via the top-level directive. Per Next.js guidance, inner "use server" is unnecessary.

 export async function promoteToPro() {
-	"use server";
 

27-28: Remove redundant "use server" here as well

Same rationale as above.

 export async function demoteFromPro() {
-	"use server";
 

18-23: Also set related Stripe fields to a consistent dev state

To prevent partial/inconsistent state, consider setting price and clearing third-party fields when promoting in dev.

 		.set({
 			stripeCustomerId: "development",
 			stripeSubscriptionId: "development",
 			stripeSubscriptionStatus: "active",
+			stripeSubscriptionPriceId: "development",
+			thirdPartyStripeSubscriptionId: null,
 		})

Confirm these fields are used in entitlement checks; adjust values if a specific dev price id exists.


36-41: Clear all Stripe-related fields on demotion

Mirror the promote path to avoid lingering identifiers.

 		.set({
 			stripeCustomerId: null,
 			stripeSubscriptionId: null,
 			stripeSubscriptionStatus: null,
+			stripeSubscriptionPriceId: null,
+			thirdPartyStripeSubscriptionId: null,
 		})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fdb412f and a575067.

📒 Files selected for processing (2)
  • apps/web/app/Layout/devtoolsServer.ts (1 hunks)
  • apps/web/app/Layout/providers.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/Layout/devtoolsServer.ts
  • apps/web/app/Layout/providers.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/Layout/devtoolsServer.ts
  • apps/web/app/Layout/providers.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/Layout/devtoolsServer.ts
  • apps/web/app/Layout/providers.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/Layout/devtoolsServer.ts
  • apps/web/app/Layout/providers.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/Layout/devtoolsServer.ts
  • apps/web/app/Layout/providers.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/Layout/devtoolsServer.ts
  • apps/web/app/Layout/providers.tsx
🧬 Code graph analysis (2)
apps/web/app/Layout/devtoolsServer.ts (2)
packages/database/index.ts (1)
  • db (30-35)
packages/database/schema.ts (1)
  • users (46-94)
apps/web/app/Layout/providers.tsx (1)
apps/web/app/Layout/devtoolsServer.ts (2)
  • promoteToPro (8-24)
  • demoteFromPro (26-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (1)
apps/web/app/Layout/devtoolsServer.ts (1)

11-13: Dev-only guard looks good

Explicitly blocking non-dev usage is correct for these actions.

If this might be used in preview/staging where NODE_ENV=production, ensure the UI is hidden (it is) and consider an environment flag if you need to enable it there.

@oscartbeaumont oscartbeaumont merged commit 0720f67 into main Sep 24, 2025
16 checks passed
@oscartbeaumont oscartbeaumont deleted the cap-pro-button branch September 24, 2025 07:38
@coderabbitai coderabbitai bot mentioned this pull request Oct 7, 2025
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