Skip to content

Add payment system #3094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 46 commits into from
Jun 17, 2025
Merged

Add payment system #3094

merged 46 commits into from
Jun 17, 2025

Conversation

phatgg221
Copy link
Collaborator

@phatgg221 phatgg221 commented Jun 15, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive billing and subscription management system for workspaces, including a new billing page, sidebar tab, and payment success screen.
    • Users can view current subscription details, upgrade plans, payment methods, and payment history.
    • Added support for purchasing and managing subscriptions via Polar payment integration.
    • Implemented automated seat usage synchronization and webhook handling for subscription events.
    • Added workspace subscription database support with secure access controls.
  • Localization

    • Added "Billing" sidebar tab translations for English and Vietnamese.
  • Chores

    • Added new environment variable placeholders for payment integration.
    • Updated workspace package dependencies to include payment functionality.
    • Updated configuration files to support new payment features and environment variables.
  • Documentation

    • Introduced new types and API documentation for payment and subscription handling.

Copy link
Contributor

coderabbitai bot commented Jun 15, 2025

Warning

Rate limit exceeded

@vhpx has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 46 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between b4c7261 and 6a2ba48.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • apps/db/supabase/migrations/20250616135112_add_platform_services.sql (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/page.tsx (1 hunks)
  • packages/types/src/supabase.ts (24 hunks)

Walkthrough

This update introduces a comprehensive billing and subscription management system for workspaces. It adds new database tables and types for subscriptions, implements backend API routes for payments, webhooks, and usage synchronization, and provides frontend UI components and pages for billing management. Supporting utilities, localization, and configuration files are also updated or added.

Changes

File(s) / Group Change Summary
apps/db/supabase/migrations/20250616064232_add_workspace_subscriptions.sql,
packages/types/src/supabase.ts
Adds new enum subscription_status, table workspace_subscription, function check_ws_creator, and updates type definitions for subscriptions and argument order for several functions.
apps/db/supabase/migrations/20250616135112_add_platform_services.sql Alters services column in public.users table to be NOT NULL with default value.
apps/web/.env.example,
turbo.json
Adds new environment variables for Polar payment integration; removes Google-related variables from turbo config.
apps/web/messages/en.json,
apps/web/messages/vi.json
Adds "billing" sidebar tab translations for English and Vietnamese.
apps/web/package.json Adds @tuturuuu/payment as a workspace dependency.
apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/billing-client.tsx Introduces BillingClient React component for displaying and managing workspace billing details and upgrades.
apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/data-polar-checkout.tsx Adds PurchaseLink React component for initiating Polar checkout flows.
apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/page.tsx Implements billing page: fetches subscription/product data, combines for UI, and displays payment history.
apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/success/page.tsx Adds payment success page: fetches subscription info and displays confirmation and next steps.
apps/web/src/app/[locale]/(dashboard)/[wsId]/layout.tsx Adds "billing" tab to sidebar navigation.
apps/web/src/app/api/[wsId]/[productId]/payment/route.ts New API route to create a Polar checkout session and redirect to payment.
apps/web/src/app/api/cron/sync-usage/route.ts New API route for daily seat usage synchronization with Polar Meter.
apps/web/src/app/api/webhooks/route.ts New webhook handler for subscription events: upserts subscription data and reports usage to Polar.
apps/web/src/lib/logger.ts Adds logger utility with info and error methods.
apps/web/src/lib/payment.ts Adds and exports a configured dodopayments instance.
apps/web/src/lib/polar.ts Adds and exports a configured api instance of Polar.
apps/web/src/types/api-types.ts Adds new types for payment, subscription, webhook payloads, and database schema.
packages/payment/package.json Adds new @tuturuuu/payment package with exports and dependencies for Polar and Dodo Payments.
packages/payment/eslint.config.mjs Adds flat ESLint config compatible with React and TypeScript.
packages/payment/tsconfig.json Adds TypeScript config extending base React library settings.
packages/payment/src/polar/checkout/embed.ts Re-exports all from @polar-sh/checkout/embed.
packages/payment/src/polar/index.ts Re-exports all from @polar-sh/sdk.
packages/payment/src/polar/next/index.ts Re-exports all from @polar-sh/nextjs.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WebApp
    participant Supabase
    participant PolarAPI

    User->>WebApp: Navigates to Billing Page
    WebApp->>Supabase: Fetch workspace subscription
    WebApp->>PolarAPI: Fetch product listings
    WebApp->>Supabase: Check if user is workspace creator
    WebApp-->>User: Render Billing UI with plans, status, upgrade options

    User->>WebApp: Selects Upgrade Plan
    WebApp->>PolarAPI: Create checkout session (via API route)
    PolarAPI-->>WebApp: Return checkout URL
    WebApp-->>User: Redirect to Polar checkout

    PolarAPI->>WebApp: Webhook (subscription active/canceled)
    WebApp->>Supabase: Upsert subscription data
    WebApp->>PolarAPI: Report usage (seat count)
Loading

Suggested labels

upskii

Poem

Hopping through fields of code so bright,
A billing system takes its flight!
Subscriptions tracked, payments flow,
With Polar and Dodo in tow.
Workspaces cheer, their plans now clear—
A rabbit’s dream: no billing fear!
(。•̀ᴗ-)✧

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch feat/payment-methods

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

graphite-app bot commented Jun 15, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

Copy link

codecov bot commented Jun 15, 2025

Codecov Report

Attention: Patch coverage is 0.22148% with 901 lines in your changes missing coverage. Please review.

Project coverage is 0.82%. Comparing base (9fdceac) to head (6a2ba48).
Report is 47 commits behind head on main.

Files with missing lines Patch % Lines
...c/app/[locale]/(dashboard)/[wsId]/billing/page.tsx 0.00% 255 Missing and 1 partial ⚠️
[...ale]/(dashboard)/[wsId]/billing/billing-client.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/3094?src=pr&el=tree&filepath=apps%2Fweb%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%5BwsId%5D%2Fbilling%2Fbilling-client.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy93ZWIvc3JjL2FwcC9bbG9jYWxlXS8oZGFzaGJvYXJkKS9bd3NJZF0vYmlsbGluZy9iaWxsaW5nLWNsaWVudC50c3g=) 0.00% 236 Missing and 1 partial ⚠️
[...ocale]/(dashboard)/[wsId]/billing/success/page.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/3094?src=pr&el=tree&filepath=apps%2Fweb%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%5BwsId%5D%2Fbilling%2Fsuccess%2Fpage.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy93ZWIvc3JjL2FwcC9bbG9jYWxlXS8oZGFzaGJvYXJkKS9bd3NJZF0vYmlsbGluZy9zdWNjZXNzL3BhZ2UudHN4) 0.00% 211 Missing and 1 partial ⚠️
apps/web/src/app/api/webhooks/route.ts 0.00% 91 Missing and 1 partial ⚠️
...(dashboard)/[wsId]/billing/data-polar-checkout.tsx 0.00% 46 Missing and 1 partial ⚠️
...eb/src/app/api/[wsId]/[productId]/payment/route.ts 0.00% 26 Missing and 1 partial ⚠️
...web/src/app/[locale]/(dashboard)/[wsId]/layout.tsx 0.00% 8 Missing ⚠️
apps/web/src/lib/logger.ts 0.00% 7 Missing and 1 partial ⚠️
apps/web/src/lib/payment.ts 0.00% 4 Missing and 1 partial ⚠️
apps/web/src/lib/polar.ts 0.00% 4 Missing and 1 partial ⚠️
... and 4 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3094      +/-   ##
==========================================
- Coverage    0.83%    0.82%   -0.01%     
==========================================
  Files        2522     2537      +15     
  Lines      315057   315961     +904     
  Branches     3023     3038      +15     
==========================================
+ Hits         2619     2621       +2     
- Misses     310287   311176     +889     
- Partials     2151     2164      +13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @phatgg221, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces the foundational structure for billing and payment processing within the application. It adds a dedicated billing page in the workspace dashboard, sets up integrations with Polar and DodoPayments SDKs, and includes initial API routes for handling checkouts and webhooks. The changes provide a user interface to view plan details, explore upgrade options, and see payment history, along with a success page for completed transactions.

Highlights

  • Billing Page Implementation: Introduced a new /billing page within the workspace dashboard, including a client-side component (billing-client.tsx) to display current plan details, upgrade options, and payment method information using mock data.
  • Payment Gateway Integration Setup: Added dependencies and initial setup for integrating with Polar and DodoPayments SDKs, including dedicated files (src/lib/polar.ts, src/lib/payment.ts) for client initialization.
  • Checkout and Webhook Routes: Created new API routes (/api/[wsId]/[productId]/payment and /api/webhooks) intended for initiating payment checkouts via Polar and handling webhook events (like subscription status changes).
  • Billing Success Page: Added a new /billing/success page to provide a confirmation and summary after a successful payment, using mock data.
  • UI and Navigation Updates: Added 'Billing' translation keys for English and Vietnamese and included a 'Billing' link with an icon in the main dashboard sidebar navigation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configureGemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces payment methods with UI components, checkout integration, and API routes. The review identified areas needing attention: placeholder logic, hardcoded configurations, a commented-out payment processing route, and unacknowledged webhook handlers. Addressing these issues is essential for deployment.

@vhpx vhpx changed the title Feat/payment methods Add payment system Jun 15, 2025
vhpx
vhpx previously approved these changes Jun 17, 2025
Copy link
Member

@vhpx vhpx left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks @phatgg221.

@vhpx vhpx marked this pull request as ready for review June 17, 2025 16:49
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: 12

🔭 Outside diff range comments (1)
apps/web/src/app/api/cron/sync-usage/route.ts (1)

1-79: Entire route is commented-out – ship either working code or delete the file

A source file that only contains commented code ships dead weight, confuses the reader, and may be stripped by tree-shaking in unpredictable ways. Either:

  1. Restore the implementation so export async function GET() is actually exported; or
  2. Delete the file until the cron endpoint is ready.

Keeping placeholder code in main undermines maintainability and violates KISS.

♻️ Duplicate comments (12)
apps/web/src/lib/polar.ts (1)

3-6: Parameterize server environment & secure token
Avoid hardcoding server: 'sandbox' and silent empty-token fallback. Use env vars to control both, e.g.:

 export const api = new Polar({
-  accessToken: process.env.NEXT_PUBLIC_POLAR_ACCESS_TOKEN || '',
-  server: 'sandbox',
+  accessToken: process.env.NEXT_PUBLIC_POLAR_ACCESS_TOKEN ?? (() => { throw new Error('NEXT_PUBLIC_POLAR_ACCESS_TOKEN is not set'); })(),
+  server: process.env.POLAR_SERVER === 'production' ? 'production' : 'sandbox',
 });
apps/web/src/lib/payment.ts (1)

3-6: Make environment and API key handling robust
Hardcoding environment: 'test_mode' and defaulting to '' hides configuration issues. Consider:

 export const dodopayments = new DodoPayment({
-  bearerToken: process.env.DODO_API_KEY || '',
-  environment: 'test_mode',
+  bearerToken: process.env.DODO_API_KEY ?? (() => { throw new Error('DODO_API_KEY is not set'); })(),
+  environment: process.env.DODO_ENVIRONMENT === 'live' ? 'live_mode' : 'test_mode',
 });
apps/web/src/app/api/[wsId]/[productId]/payment/route.ts (1)

17-24: Hard-coded successUrl will break in non-local environments

Same concern flagged earlier – still unresolved.

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/data-polar-checkout.tsx (1)

20-33: Hard-coded test email still present
The customerEmail prop is ignored and the checkout URL embeds t@test.com.

This has been flagged before; please switch to the real value or omit the param.

-const testEmail = 't@test.com';
-const checkoutUrl = `/api/${wsId}/${productId}/payment?productId=${productId}&customerEmail=${testEmail}`;
+const checkoutUrl = `/api/${wsId}/${productId}/payment?productId=${productId}` +
+  (customerEmail ? `&customerEmail=${encodeURIComponent(customerEmail)}` : '');
apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/page.tsx (1)

132-151: Static payment history is placeholder data

paymentHistory is hard-coded; production users will always see the same three invoices. Fetch real invoice data from Polar or Supabase, or clearly mark the section as demo-only.

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/success/page.tsx (1)

170-181: “Download Receipt” button is non-functional

The button renders but has no onClick or href. Either hook it to the actual invoice PDF URL or remove it until implemented.

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/billing-client.tsx (4)

104-112: Using array index as React key risks remounts

Keys must be stable; use the feature string itself.

-{currentPlan.features?.map((feature, index) => (
-  <li key={index} …>
+{currentPlan.features?.map((feature) => (
+  <li key={feature} …>

187-192: Same index-key issue in upgrade plan features


208-213: Hard-coded customer email in checkout link

Re-use the real user email or omit the parameter to avoid PII leaks and test artefacts.


145-151: “Update payment method” button is a stub

Replace the placeholder with a dialog / redirect to your payment portal.

apps/web/src/app/api/webhooks/route.ts (2)

13-14: Webhook secret must be mandatory

Defaulting to '' silently disables signature verification.
Throw if POLAR_WEBHOOK_SECRET is missing, as suggested in the previous review.


100-108: Missing success response yields 500

After completing all work the handler falls out without returning anything, so the framework responds with 500.
Add an explicit 200:

-      console.log(`Webhook: Subscription active for workspace ${ws_id}.`);
+      console.log(`Webhook: Subscription active for workspace ${ws_id}.`);
+      return new Response('Subscription processed', { status: 200 });
🧹 Nitpick comments (12)
apps/web/.env.example (1)

43-47: Add trailing newline and reorder Payment env vars
Lint tools expect a blank line at EOF. Also, for clarity, consider listing public variables before secrets:

- POLAR_WEBHOOK_SECRET=YOUR_POLAR_WEBHOOK_SECRET
- NEXT_PUBLIC_POLAR_ACCESS_TOKEN=YOUR_NEXT_PUBLIC_POLAR_ACCESS_TOKEN
+ NEXT_PUBLIC_POLAR_ACCESS_TOKEN=YOUR_NEXT_PUBLIC_POLAR_ACCESS_TOKEN
+ POLAR_WEBHOOK_SECRET=YOUR_POLAR_WEBHOOK_SECRET
  • Add an empty line after the last entry.
apps/web/src/lib/polar.ts (1)

3-6: Add tests for Polar client instantiation
Codecov indicates these lines lack coverage. Please add unit tests to verify api is created with the correct token and server fallback. I can help generate example tests if needed.

apps/web/src/lib/payment.ts (1)

3-6: Cover DodoPayment instantiation with tests
The new client setup isn't covered by existing tests (codecov flagged). Add tests to assert proper environment selection and error handling for missing API key.

apps/web/src/lib/logger.ts (1)

2-8: Consider formalising structured logging & widen log levels

Inline console.* calls work, but they quickly get messy once log volume grows.
A thin wrapper around a battle-tested lib (pino, winston) would give you:

• JSON output → easier CloudWatch / Stackdriver parsing
• Additional log levels (debug, warn) and child-logger contexts
• Automatic error stack serialisation

You can still re-export the same info / error API to keep call-sites unchanged.

packages/payment/eslint.config.mjs (1)

18-20: Why disable no-redeclare globally?

no-redeclare guards against accidental shadowing. If the rule is noisy for generated overloads you can disable it per-file with ESLint directives instead of blanket deactivation.

apps/web/src/app/api/cron/sync-usage/route.ts (1)

8-12: authorization header comparison is brittle

if (authHeader !== `Bearer ${CRON_SECRET}`) {  }

This fails for trivial formatting differences (extra spaces, different case). Prefer a constant-time comparison after splitting the scheme and token:

- if (authHeader !== `Bearer ${CRON_SECRET}`) {
+ const token = authHeader?.split(' ')[1] ?? '';
+ if (!crypto.timingSafeEqual(Buffer.from(token), Buffer.from(CRON_SECRET ?? ''))) {

Also guard against missing CRON_SECRET at boot time.

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/data-polar-checkout.tsx (1)

35-41: Prefer next/link over raw <a> for internal navigation

Using <a> forces a full page reload and loses Next.js routing benefits. Wrap the anchor with Link or use asChild from your UI lib.

-import React from 'react';-<a href={checkoutUrl} …>
+import Link from 'next/link';
+<Link href={checkoutUrl} data-polar-checkout data-polar-checkout-theme={theme} className={className}>
   {children}
-</a>
+</Link>
apps/web/src/types/api-types.ts (1)

12-17: Enum casing may not match provider

'Day' | 'Week' | 'Month' | 'Year' differs from common lowercase (day, week, …).
Ensure it mirrors the actual API, otherwise decoding will fail.

apps/db/supabase/migrations/20250616064232_add_workspace_subscriptions.sql (1)

70-85: Unused helper function

check_ws_creator(ws_id) is defined but not used in any policy. Either reference it in the INSERT policy or remove to avoid dead code.

packages/types/src/supabase.ts (3)

7920-7920: Enum duplication risk – keep Constant list in lock-step with DB enum

subscription_status is now declared twice: once in the autogenerated Enums section (l. 7920) and again inside Constants.public.Enums (l. 8074).
The two sources must always match; forgetting to re-run the code-gen after an enum change silently desynchronises the Constants helper.

Automate the Constants generation or remove the hand-rolled list to avoid divergence.

Also applies to: 8074-8074


7406-7408: check_ws_creator exposes security-critical logic – confirm return type

The Postgres function returns a boolean but gives no clue whether it throws on missing records or simply returns false.
Upstream callers should treat false as “not owner” rather than an error condition and add their own 404 / 403 handling.


8058-8103: Do not hand-edit generated type file

Changes in this file are normally produced by supabase gen types.
Manual edits (especially to Constants) will be lost on the next generation run and may introduce subtle type drift.
Prefer keeping bespoke helpers in a separate module (e.g., supabaseConstants.ts) and import them where needed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b0172d and 16b3053.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (25)
  • apps/db/supabase/migrations/20250616064232_add_workspace_subscriptions.sql (1 hunks)
  • apps/web/.env.example (1 hunks)
  • apps/web/messages/en.json (1 hunks)
  • apps/web/messages/vi.json (1 hunks)
  • apps/web/package.json (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/billing-client.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/data-polar-checkout.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/page.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/success/page.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/layout.tsx (2 hunks)
  • apps/web/src/app/api/[wsId]/[productId]/payment/route.ts (1 hunks)
  • apps/web/src/app/api/cron/sync-usage/route.ts (1 hunks)
  • apps/web/src/app/api/webhooks/route.ts (1 hunks)
  • apps/web/src/lib/logger.ts (1 hunks)
  • apps/web/src/lib/payment.ts (1 hunks)
  • apps/web/src/lib/polar.ts (1 hunks)
  • apps/web/src/types/api-types.ts (1 hunks)
  • packages/payment/eslint.config.mjs (1 hunks)
  • packages/payment/package.json (1 hunks)
  • packages/payment/src/polar/checkout/embed.ts (1 hunks)
  • packages/payment/src/polar/index.ts (1 hunks)
  • packages/payment/src/polar/next/index.ts (1 hunks)
  • packages/payment/tsconfig.json (1 hunks)
  • packages/types/src/supabase.ts (22 hunks)
  • turbo.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/web/src/app/api/[wsId]/[productId]/payment/route.ts (1)
apps/web/src/lib/polar.ts (1)
  • api (3-6)
🪛 dotenv-linter (3.3.0)
apps/web/.env.example

[warning] 43-43: [UnorderedKey] The NEXT_PUBLIC_PROXY_API_KEY key should go before the PROXY_API_KEY key


[warning] 47-47: [EndingBlankLine] No blank line at the end of the file


[warning] 47-47: [UnorderedKey] The NEXT_PUBLIC_POLAR_ACCESS_TOKEN key should go before the POLAR_WEBHOOK_SECRET key

🪛 GitHub Check: codecov/patch
apps/web/src/lib/polar.ts

[warning] 3-6: apps/web/src/lib/polar.ts#L3-L6
Added lines #L3 - L6 were not covered by tests

apps/web/src/lib/logger.ts

[warning] 2-8: apps/web/src/lib/logger.ts#L2-L8
Added lines #L2 - L8 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/layout.tsx

[warning] 38-38: apps/web/src/app/[locale]/(dashboard)/[wsId]/layout.tsx#L38
Added line #L38 was not covered by tests


[warning] 380-386: apps/web/src/app/[locale]/(dashboard)/[wsId]/layout.tsx#L380-L386
Added lines #L380 - L386 were not covered by tests

apps/web/src/app/api/[wsId]/[productId]/payment/route.ts

[warning] 2-27: apps/web/src/app/api/[wsId]/[productId]/payment/route.ts#L2-L27
Added lines #L2 - L27 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/page.tsx

[warning] 2-258: apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/page.tsx#L2-L258
Added lines #L2 - L258 were not covered by tests

apps/web/src/lib/payment.ts

[warning] 3-6: apps/web/src/lib/payment.ts#L3-L6
Added lines #L3 - L6 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/data-polar-checkout.tsx

[warning] 2-47: apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/data-polar-checkout.tsx#L2-L47
Added lines #L2 - L47 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/success/page.tsx

[warning] 2-212: apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/success/page.tsx#L2-L212
Added lines #L2 - L212 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/billing-client.tsx

[warning] 2-237: apps/web/src/app/[locale]/(dashboard)/[wsId]/billing/billing-client.tsx#L2-L237
Added lines #L2 - L237 were not covered by tests

apps/web/src/app/api/webhooks/route.ts

[warning] 2-3: apps/web/src/app/api/webhooks/route.ts#L2-L3
Added lines #L2 - L3 were not covered by tests


[warning] 7-10: apps/web/src/app/api/webhooks/route.ts#L7-L10
Added lines #L7 - L10 were not covered by tests


[warning] 12-13: apps/web/src/app/api/webhooks/route.ts#L12-L13
Added lines #L12 - L13 were not covered by tests


[warning] 15-18: apps/web/src/app/api/webhooks/route.ts#L15-L18
Added lines #L15 - L18 were not covered by tests


[warning] 21-24: apps/web/src/app/api/webhooks/route.ts#L21-L24
Added lines #L21 - L24 were not covered by tests


[warning] 26-29: apps/web/src/app/api/webhooks/route.ts#L26-L29
Added lines #L26 - L29 were not covered by tests


[warning] 31-31: apps/web/src/app/api/webhooks/route.ts#L31
Added line #L31 was not covered by tests


[warning] 33-40: apps/web/src/app/api/webhooks/route.ts#L33-L40
Added lines #L33 - L40 were not covered by tests


[warning] 43-46: apps/web/src/app/api/webhooks/route.ts#L43-L46
Added lines #L43 - L46 were not covered by tests


[warning] 48-54: apps/web/src/app/api/webhooks/route.ts#L48-L54
Added lines #L48 - L54 were not covered by tests


[warning] 56-60: apps/web/src/app/api/webhooks/route.ts#L56-L60
Added lines #L56 - L60 were not covered by tests


[warning] 62-68: apps/web/src/app/api/webhooks/route.ts#L62-L68
Added lines #L62 - L68 were not covered by tests


[warning] 71-71: apps/web/src/app/api/webhooks/route.ts#L71
Added line #L71 was not covered by tests


[warning] 73-76: apps/web/src/app/api/webhooks/route.ts#L73-L76
Added lines #L73 - L76 were not covered by tests


[warning] 78-79: apps/web/src/app/api/webhooks/route.ts#L78-L79
Added lines #L78 - L79 were not covered by tests


[warning] 81-95: apps/web/src/app/api/webhooks/route.ts#L81-L95
Added lines #L81 - L95 were not covered by tests


[warning] 97-98: apps/web/src/app/api/webhooks/route.ts#L97-L98
Added lines #L97 - L98 were not covered by tests


[warning] 100-109: apps/web/src/app/api/webhooks/route.ts#L100-L109
Added lines #L100 - L109 were not covered by tests


[warning] 111-111: apps/web/src/app/api/webhooks/route.ts#L111
Added line #L111 was not covered by tests


[warning] 113-116: apps/web/src/app/api/webhooks/route.ts#L113-L116
Added lines #L113 - L116 were not covered by tests

🔇 Additional comments (15)
packages/payment/src/polar/checkout/embed.ts (1)

1-1: Simple Re-export Facade
This module cleanly re-exports everything from @polar-sh/checkout/embed, providing a centralized entrypoint.

apps/web/package.json (1)

48-48: Add @tuturuuu/payment Workspace Dependency
Including the new payment package aligns with the billing integration. Make sure the lockfile is updated to reflect this addition.

apps/web/messages/en.json (1)

557-557: Add translation key for billing sidebar tab.

The "billing": "Billing" entry under sidebar_tabs correctly introduces the new sidebar label for the billing feature and follows existing naming conventions.

turbo.json (2)

16-18: AI summary inconsistency: Google env vars removal not reflected.

The AI-generated summary states that Google-related environment variables were removed, but they still exist on lines 16–18. Please confirm if those should indeed be dropped or retained.

Also applies to: 40-40

Likely an incorrect or invalid review comment.


40-40: Add POLAR_WEBHOOK_SECRET to globalEnv

Introduces the new webhook secret for Polar integration. Ensure corresponding updates are made in .env.example, CI/CD settings, and project documentation.

packages/payment/src/polar/next/index.ts (1)

1-1: Proxy export for @polar-sh/nextjs

This re-export simplifies import paths across the monorepo. Verify that @polar-sh/nextjs is declared in the package’s dependencies and that the files/exports field in package.json includes this path.

apps/web/messages/vi.json (2)

568-568: Approve insertion of the new sidebar billing tab.
The "billing": "Thanh toán" entry correctly maps the new billing route in the workspace sidebar. JSON remains valid and consistent with feature rollout.


615-615: Approve translation in settings-tabs.
Adding "billing": "Thanh toán" under settings-tabs aligns with the sidebar label and ensures consistency across the Vietnamese UI.

packages/payment/src/polar/index.ts (1)

1-1: Re-export Polar SDK via proxy module
This proxy correctly exposes the full @polar-sh/sdk surface. Ensure that consumers tree-shake unused exports to keep bundle size optimal.

packages/payment/tsconfig.json (1)

1-11: TSConfig setup is correct
The config extends the shared React library settings, sets baseUrl, path alias for @tuturuuu/payment/*, and correctly includes/excludes directories. No changes needed.

packages/payment/package.json (1)

13-18: Pinning very new versions – verify they are published & semver-safe

All dependencies are set to caret ranges on recent versions. Run CI with npm ci and ensure:

  1. versions actually exist on npm,
  2. no peer-dependency conflicts surface.
apps/web/src/app/[locale]/(dashboard)/[wsId]/layout.tsx (1)

38-38: Stale import ordering comment resolved – looks good

Receipt icon is correctly imported next to other icons.

apps/web/src/app/api/webhooks/route.ts (1)

81-88: Verify customer identifier path

payload.data.customer.id may be payload.data.customerId depending on Polar’s schema.
Please double-check to avoid undefined errors.

apps/web/src/types/api-types.ts (1)

1-5: Confirm library mismatch

Types are pulled from dodopayments/*, whereas runtime code relies on @tuturuuu/payment.
If Polar replaces Dodo, consider removing these legacy imports to avoid type drift.

packages/types/src/supabase.ts (1)

6162-6211: ```shell
#!/bin/bash

List all workspace_* table definitions in the Supabase types file

grep -R "^[[:space:]]workspace_[a-z_]:" -n packages/types/src/supabase.ts


</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

vhpx
vhpx previously approved these changes Jun 17, 2025
@vhpx vhpx enabled auto-merge June 17, 2025 17:04
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: 2

🧹 Nitpick comments (1)
packages/types/src/supabase.ts (1)

1-8103: Generated file – avoid manual tweaks

Just a reminder: this file is generated by supabase gen types.
Any manual edits (e.g. the relationship note above) must be fixed in the SQL schema / migration so the next code-gen run keeps them; otherwise they’ll be overwritten.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16b3053 and b4c7261.

📒 Files selected for processing (3)
  • apps/db/supabase/migrations/20250616064232_add_workspace_subscriptions.sql (1 hunks)
  • apps/db/supabase/migrations/20250616135112_add_platform_services.sql (1 hunks)
  • packages/types/src/supabase.ts (23 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/db/supabase/migrations/20250616064232_add_workspace_subscriptions.sql
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Deploy-Preview
  • GitHub Check: Deploy-Preview
  • GitHub Check: Deploy-Preview
  • GitHub Check: Deploy-Preview
  • GitHub Check: Deploy-Preview
  • GitHub Check: Run tests and collect coverage
  • GitHub Check: Verify generated types
🔇 Additional comments (3)
packages/types/src/supabase.ts (3)

4513-4534: Non-nullable services column – double-check upstream writes

users.services is now typed as a non-nullable platform_service[] in Row, but remains optional in Insert / Update.
If any caller still explicitly sends null (rather than omitting the property and relying on the default array[]), the runtime insert/update will now fail at the DB layer.

- services?: Database['public']['Enums']['platform_service'][];
+ // keep optional but forbid null to surface early
+ services?: NonNullable<
+   Database['public']['Enums']['platform_service'][]
+ >;

Run your integration tests (or grep for services: null) to make sure no payloads violate the new constraint.
Otherwise this change looks correct.


7905-7920: Enum added correctly – LGTM

The new subscription_status enum is declared in both the union type and the Constants helper array; nothing else to flag here.


7402-7405: Confirm check_ws_creator RPC is deployed

Types are in place, but make sure the new check_ws_creator(ws_id uuid) function is actually created and SECURITY DEFINER / RLS-safe in the migration, otherwise clients will get 404/permission errors.

vhpx
vhpx previously approved these changes Jun 17, 2025
@vhpx vhpx merged commit bdb0d3c into main Jun 17, 2025
19 checks passed
@vhpx vhpx deleted the feat/payment-methods branch June 17, 2025 17:27
@coderabbitai coderabbitai bot mentioned this pull request Jun 18, 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