Skip to content

Add stripe billing logic #190

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 29 commits into from
Feb 13, 2025
Merged

Add stripe billing logic #190

merged 29 commits into from
Feb 13, 2025

Conversation

msukkari
Copy link
Contributor

@msukkari msukkari commented Feb 13, 2025

New required env vars in web package

  • NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
  • STRIPE_SECRET_KEY
  • STRIPE_PRODUCT_ID

Summary by CodeRabbit

  • New Features
    • Enhanced subscription and billing management with new checkout flows, trial notifications, and customer portal access.
    • Added components for onboarding, organization creation, and member invite management.
  • UI Enhancements
    • Revamped navigation, footer, sidebar, and error displays for improved layout and user feedback.
  • Improvements
    • Updated backend operations and database structure for smoother payment integration.
    • Upgraded dependencies and refined styles for enhanced performance and consistency.

customer: org.stripeCustomerId!
})

if (subscriptions.data.length === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it the case that we will only ever have a single subscription?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, if a subscription is cancelled (including if the trial ends) the subscription will not be fetched here and we return notFound

Copy link

coderabbitai bot commented Feb 13, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The changes update the backend control flow by converting a synchronous poll loop to an asynchronous one and extend the database schema by adding a new column for Stripe data. The Prisma schema now includes an optional Stripe customer ID field. In the web project, dependency versions are updated, new functions are added for authentication, organization management, and Stripe integration, and several UI components are introduced or updated. The settings, onboarding, and redeem flows have been modified for improved error handling and subscription management, and styling enhancements are applied via updated CSS and Tailwind configurations.

Changes

File(s) Change Summary
packages/backend/src/main.ts Changed synchronous call to asynchronous (await repoManager.blockingPollLoop()).
packages/db/prisma/migrations/...migration.sql,
packages/db/prisma/schema.prisma
Added new stripeCustomerId column/field to the Org table/model.
packages/web/package.json Updated dependency versions and added new Stripe-related dependencies.
packages/web/src/actions.ts Added new functions for auth check, org creation (with stripeCustomerId), Stripe session management, subscription handling, and member/org management; updated function signatures.
packages/web/src/app/[domain]/components/footer.tsx,
packages/web/src/app/[domain]/components/navigationMenu.tsx,
packages/web/src/app/[domain]/components/payWall/*
Introduced new UI components: Footer, NavigationMenu (with trial status), CheckoutButton, EnterpriseContactUsButton, and PaywallCard with enhanced UI and subscription flow.
packages/web/src/app/[domain]/layout.tsx,
packages/web/src/app/[domain]/page.tsx
Modified layout components to conditionally render content based on subscription status and extracted footer into its own component.
packages/web/src/app/[domain]/settings/**/* Enhanced settings with new billing pages, manage subscription button, invite/member management components, and updated sidebar navigation.
packages/web/src/app/login/page.tsx,
packages/web/src/app/onboard/*,
packages/web/src/app/redeem/page.tsx
Updated authentication, onboarding, and redeem flows with new error handling, organization creation, and Stripe session integration.
packages/web/src/app/globals.css,
packages/web/tailwind.config.ts
Introduced new CSS custom properties for sidebar styling and restructured Tailwind theme configuration.
packages/web/src/components/hooks/use-mobile.tsx,
packages/web/src/components/ui/*
Added a new hook (useIsMobile) and updated UI components (button, input, sheet, sidebar) for improved layout and behavior.
packages/web/src/lib/* Added Stripe integration, new environment variable handling (with non-null assertion for AUTH_URL), additional error codes, and service error functions.
packages/web/src/app/layout.tsx Minor formatting change: added a newline character.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant CB as CheckoutButton Component
    participant A as actions.ts (getSubscriptionCheckoutRedirect)
    participant S as Stripe API

    U->>CB: Click "Renew Membership"
    CB->>A: Request checkout redirect URL (domain)
    A->>S: Fetch checkout session details
    S-->>A: Return redirect URL / error
    A-->>CB: Return URL or service error
    alt Success
        CB->>U: Redirect browser to checkout URL
    else Error
        CB->>Console: Log error message
    end
Loading
sequenceDiagram
    participant U as User
    participant OB as Onboarding Component
    participant A as actions.ts (auth & createOrg)
    participant S as Stripe API

    U->>OB: Access Onboarding Page
    OB->>A: Check authentication via isAuthed
    alt Not Authenticated
        OB->>U: Redirect to Login
    else Authenticated
        OB->>U: Render OrgCreateForm or TrialCard
        U->>OB: Submit organization details/acknowledge trial
        OB->>A: Call setupInitialStripeCustomer (with org details)
        A->>S: Request Stripe session
        S-->>A: Return Stripe session info
        OB->>A: Call createOrg with stripeCustomerId
        A-->>OB: Return organization creation result or error
        alt Success
            OB->>U: Redirect to Home
        else Failure
            OB->>U: Render ErrorPage
        end
    end
Loading

Poem

I'm a rabbit hopping through the code,
Async calls and Stripe integrations unfold.
New UIs sparkle, settings refined,
With sleek, updated flows all intertwined.
Error checks and migrate trails in tow,
I bounce with joy at each commit's glow.
Happy coding from your rabbit amigo! 🐇✨


🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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.

@brendan-kellam
Copy link
Contributor

@coderabbitai review

Copy link

coderabbitai bot commented Feb 13, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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: 16

🧹 Nitpick comments (38)
packages/web/src/app/[domain]/settings/components/memberTable.tsx (1)

18-28: Consider safer type handling for member properties.

The non-null assertions (!) could lead to runtime errors if the data is null. Consider using optional chaining or providing default values.

-                id: member.id!,
-                name: member.name!,
-                email: member.email!,
-                role: member.role!,
+                id: member.id ?? '',
+                name: member.name ?? 'Unknown',
+                email: member.email ?? '',
+                role: member.role ?? 'Member',
packages/web/src/app/[domain]/settings/components/memberTableColumns.tsx (2)

39-45: Consider enhancing email display.

The email column could benefit from additional formatting or validation to improve readability and user experience.

             cell: ({ row }) => {
                 const member = row.original;
-                return <div>{member.email}</div>;
+                return (
+                    <div className="font-mono text-sm text-muted-foreground">
+                        {member.email.toLowerCase()}
+                    </div>
+                );
             }

53-134: Add loading state during member removal.

The remove member functionality should indicate when the removal is in progress to prevent multiple clicks and provide better user feedback.

+                                const [isLoading, setIsLoading] = useState(false);
                                 <Button 
                                     variant="destructive" 
                                     className="hover:bg-destructive/90"
+                                    disabled={isLoading}
                                     onClick={async () => {
+                                        setIsLoading(true);
                                         try {
                                             const response = await removeMember(member.id, domain);
                                             if (isServiceError(response)) {
                                                 toast({
                                                     description: `❌ Failed to remove member. Reason: ${response.message}`
                                                 });
                                             } else {
                                                 toast({
                                                     description: `✅ Member removed successfully.`
                                                 });

                                                 router.refresh();
                                             }
+                                        } finally {
+                                            setIsLoading(false);
+                                        }
                                     }}
                                 >
-                                    Remove Member
+                                    {isLoading ? 'Removing...' : 'Remove Member'}
                                 </Button>
packages/web/src/app/[domain]/settings/components/inviteTable.tsx (1)

37-38: Consider removing redundant font-normal class.

The font-normal class can be removed as it's the default font weight.

-            <h4 className="text-lg font-normal">Invites</h4>
+            <h4 className="text-lg">Invites</h4>
packages/web/src/app/onboard/page.tsx (1)

13-22: Consider adding a loading state.

Currently, while awaiting the result of isAuthed(), users might briefly see the onboarding UI if the request is slow. Introducing a loading indicator could improve the user experience:

 useEffect(() => {
+   setIsLoading(true);
    const redirectIfNotAuthed = async () => {
        const authed = await isAuthed();
        if (!authed) {
            router.push("/login");
        }
+       setIsLoading(false);
    }
    redirectIfNotAuthed();
}, []);
packages/web/src/app/onboard/complete/page.tsx (1)

16-26: Session retrieval logic is fine.

You may consider showing a small loading component if authentication validation is lengthy.

packages/web/src/actions.ts (3)

464-515: getSubscriptionCheckoutRedirect covers new subscription scenarios.

If an existing subscription is partially active, consider how you’d handle upgrades or plan changes. Might need separate logic for expansions versus brand-new subscriptions.


544-563: fetchSubscription returns the first subscription only.

If you plan to support multiple subscriptions per org, refactor to handle multiple items.


645-661: getSubscriptionData is useful for per-seat plans.

Consider how to handle multiple subscription items if you add more seats/products.

packages/web/src/components/ui/sidebar.tsx (5)

86-90: Consider reading the cookie on mount for a consistent user experience.
Currently, you're writing the sidebar's open state to a cookie without reading it during initialization, causing the UI to ignore saved preferences on page reload or navigation. Parsing the cookie on mount would preserve the user's preferred sidebar state.


99-113: Evaluate alternative keyboard shortcuts for better accessibility.
While Ctrl/Cmd + B toggling the sidebar is convenient, it can conflict with browser/editor shortcuts (e.g., bold formatting in many editors). Consider offering a user-customizable shortcut or implementing a more obscure combination to reduce collisions.


294-312: Confirm the clickable rail behavior matches user expectations.
Toggling the sidebar by clicking the rail might surprise users if they're not expecting a draggable or clickable edge. Consider adding a visible handle or more explicit UI cues to communicate that this area is interactive.


653-679: Avoid random values if snapshot tests are used.
Using the random width inside SidebarMenuSkeleton can cause test flakiness in snapshot-based testing scenarios. If you perform visual regression or snapshot tests, replace random width with a deterministic pattern or remove it during testing.


720-734: Check focus states for sub-menu items.
SidebarMenuSubButton elements rely on standard anchor focus. In some cases, re-styling or additional accessibility features might be warranted, such as visually recognizable focus indicators to comply with WCAG standards.

packages/web/src/app/[domain]/components/payWall/enterpriseContactUsButton.tsx (2)

6-8: Use a safer mailto approach if needed.
window.location.href = "mailto:..." is a straightforward choice but can be blocked in certain environments or lead to unexpected behavior for users without a configured email client. If relevant, consider an in-app contact form as a fallback.


10-14: Consider analytics or logging for support inquiries.
If measuring enterprise demand is important, integrate a lightweight logging call before redirecting. This insight can help your team follow up effectively or analyze user engagement with the “Contact Us” CTA.

packages/web/src/components/hooks/use-mobile.tsx (2)

3-3: Consider using a custom type for the breakpoint.

Define the breakpoint using a custom type to improve maintainability and reusability.

-const MOBILE_BREAKPOINT = 768
+type Breakpoint = 768
+const MOBILE_BREAKPOINT: Breakpoint = 768

18-18: Simplify the return statement.

The double negation operator !! is unnecessary since isMobile is already a boolean.

-  return !!isMobile
+  return isMobile ?? false
packages/web/src/app/[domain]/settings/components/sidebar-nav.tsx (1)

16-44: Add accessibility attributes to the navigation.

The implementation looks good but could benefit from improved accessibility.

     <nav
       className={cn(
         "flex space-x-2 lg:flex-col lg:space-x-0 lg:space-y-1",
         className
       )}
+      aria-label="Settings navigation"
       {...props}
     >
       {items.map((item) => (
         <Link
           key={item.href}
           href={item.href}
           className={cn(
             buttonVariants({ variant: "ghost" }),
             pathname === item.href
               ? "bg-muted hover:bg-muted"
               : "hover:bg-transparent hover:underline",
             "justify-start"
           )}
+          aria-current={pathname === item.href ? "page" : undefined}
         >
packages/web/src/app/onboard/components/errorPage.tsx (1)

8-37: Consider making error content configurable.

  1. Move the support email to configuration.
  2. Make error message dynamic to handle different error scenarios.

Apply this diff to improve configurability:

+interface ErrorPageProps {
+  title?: string;
+  message?: string;
+  supportEmail?: string;
+}
+
-export function ErrorPage() {
+export function ErrorPage({
+  title = "Organization Creation Failed",
+  message = "We encountered an error while creating your organization. Please try again.",
+  supportEmail = "team@sourcebot.dev"
+}: ErrorPageProps) {
   const router = useRouter()

   return (
     <div className="min-h-screen w-full flex items-center justify-center p-4">
       <Card className="w-full max-w-md">
         <CardContent className="pt-12 pb-8 px-8 flex flex-col items-center text-center">
           <div className="mb-6">
             <XCircle className="h-16 w-16 text-red-500" />
           </div>
-          <h1 className="text-2xl font-bold mb-8">Organization Creation Failed</h1>
+          <h1 className="text-2xl font-bold mb-8">{title}</h1>
           <p className="text-gray-400 mb-4">
-            We encountered an error while creating your organization. Please try again.
+            {message}
           </p>
           <p className="text-gray-400 mb-8">
-            If the problem persists, please contact us at team@sourcebot.dev
+            If the problem persists, please contact us at {supportEmail}
           </p>
packages/web/src/app/[domain]/settings/layout.tsx (1)

11-27: Consider moving navigation items to configuration.

Navigation items could be moved to a separate configuration file for better maintainability and reusability.

Create a new file config/settings.ts:

export const settingsNavItems = (domain: string) => [
  {
    title: "Members",
    href: `/${domain}/settings`,
  },
  {
    title: "Billing",
    href: `/${domain}/settings/billing`,
  }
]

Then update the component:

+import { settingsNavItems } from "@/config/settings"

 export default function SettingsLayout({
   children,
   params: { domain },
 }: Readonly<{
   children: React.ReactNode;
   params: { domain: string };
 }>) {
-  const sidebarNavItems = [
-    {
-      title: "Members",
-      href: `/${domain}/settings`,
-    },
-    {
-      title: "Billing",
-      href: `/${domain}/settings/billing`,
-    }
-  ]
+  const sidebarNavItems = settingsNavItems(domain)
packages/web/src/app/[domain]/layout.tsx (1)

46-55: Enhance subscription status check and error handling.

  1. Consider caching subscription status to improve performance.
  2. Add more specific error handling for different subscription states.

Apply this diff to improve the implementation:

-    const subscription = await fetchSubscription(org.id);
-    if (isServiceError(subscription) || (subscription.status !== "active" && subscription.status !== "trialing")) {
+    try {
+        const subscription = await fetchSubscription(org.id);
+        if (isServiceError(subscription)) {
+            console.error("Failed to fetch subscription:", subscription);
+            return <ErrorPage 
+                title="Subscription Error"
+                message="We couldn't verify your subscription status. Please try again later."
+            />;
+        }
+        
+        if (subscription.status === "canceled") {
+            return (
+                <div className="flex flex-col items-center overflow-hidden min-h-screen">
+                    <NavigationMenu domain={domain} />
+                    <PaywallCard 
+                        domain={domain}
+                        message="Your subscription has been canceled. Please renew to continue."
+                    />
+                    <Footer />
+                </div>
+            );
+        }
+        
+        if (subscription.status !== "active" && subscription.status !== "trialing") {
+            return (
+                <div className="flex flex-col items-center overflow-hidden min-h-screen">
+                    <NavigationMenu domain={domain} />
+                    <PaywallCard domain={domain} />
+                    <Footer />
+                </div>
+            );
+        }
+    } catch (error) {
+        console.error("Error fetching subscription:", error);
+        return <ErrorPage 
+            title="Unexpected Error"
+            message="An unexpected error occurred. Please try again later."
+        />;
+    }

Don't forget to import the ErrorPage component:

import { ErrorPage } from "@/components/errorPage"
packages/web/src/app/[domain]/settings/components/memberInviteForm.tsx (1)

34-36: Consider improving error message readability.

The ternary operator makes the error message logic harder to read. Consider extracting the message logic for better maintainability.

-                description: res.errorCode == ErrorCode.SELF_INVITE ? res.message :`❌ Failed to create invite`
+                description: getInviteErrorMessage(res)

Add this helper function:

const getInviteErrorMessage = (error: ServiceError) => {
  if (error.errorCode === ErrorCode.SELF_INVITE) {
    return error.message;
  }
  return '❌ Failed to create invite';
};
packages/web/src/lib/serviceError.ts (1)

96-101: Enhance error message for invalid subscription.

The current message "Invalid subscription" is too generic. Consider providing more context about what makes the subscription invalid.

-        message: "Invalid subscription",
+        message: "Invalid or expired subscription. Please check your subscription status in the billing settings.",
packages/web/src/app/[domain]/settings/billing/page.tsx (2)

61-61: Consider timezone handling for billing date display.

The date conversion might show incorrect dates in different timezones. Consider using a more robust date formatting solution.

-<p className="text-sm text-muted-foreground">{new Date(subscription.nextBillingDate * 1000).toLocaleDateString()}</p>
+<p className="text-sm text-muted-foreground">{new Date(subscription.nextBillingDate * 1000).toLocaleDateString(undefined, {
+  year: 'numeric',
+  month: 'long',
+  day: 'numeric',
+  timeZone: 'UTC'
+})}</p>

70-70: Add currency formatting for billing amount.

Consider using Intl.NumberFormat for consistent currency formatting across different locales.

-<p className="text-sm text-muted-foreground">${(subscription.perSeatPrice * subscription.seats).toFixed(2)} per month</p>
+<p className="text-sm text-muted-foreground">
+  {new Intl.NumberFormat('en-US', {
+    style: 'currency',
+    currency: 'USD'
+  }).format(subscription.perSeatPrice * subscription.seats)} per month
+</p>
packages/web/src/app/[domain]/components/payWall/paywallCard.tsx (2)

9-21: Consider extracting feature lists to configuration.

Move feature lists to a configuration file for easier maintenance and potential dynamic updates.

+// config/subscription-features.ts
+export const subscriptionFeatures = {
+  team: [
+    "Index hundreds of repos from multiple code hosts (GitHub, GitLab, Gerrit, Gitea, etc.). Self-hosted code sources supported",
+    "Public and private repos supported",
+    "Create sharable links to code snippets",
+    "9x5 email support team@sourcebot.dev",
+  ],
+  enterprise: [
+    "All Team features",
+    "Dedicated Slack support channel",
+    "Single tenant deployment",
+    "Advanced security features",
+  ]
+};

27-38: Enhance image loading optimization.

Consider using next/image's sizes prop for better responsive image loading.

         <Image
           src={logoDark}
           className="h-18 md:h-40 w-auto hidden dark:block"
           alt={"Sourcebot logo"}
           priority={true}
+          sizes="(max-width: 768px) 72px, 160px"
         />
packages/web/src/app/login/page.tsx (1)

58-60: Consider adding loading state for sign-in process.

Add loading state to improve user experience during authentication.

+                                const [isLoading, setIsLoading] = useState(false);
                                 try {
+                                    setIsLoading(true);
                                     await signIn(provider.id, {
                                         redirectTo: props.searchParams?.callbackUrl ?? "/"
                                     })
                                 } catch (error) {
+                                    setIsLoading(false);
packages/web/src/components/ui/sheet.tsx (2)

33-50: Consider adding a size variant for the sheet.

The sheet variants currently only handle positioning. Consider adding a size variant to control the width/height of the sheet for different use cases.

 const sheetVariants = cva(
   "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
   {
     variants: {
       side: {
         top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
         bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
         left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
         right: "inset-y-0 right-0 h-full w-3/4  border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
       },
+      size: {
+        sm: "sm:max-w-sm",
+        md: "sm:max-w-md",
+        lg: "sm:max-w-lg",
+        xl: "sm:max-w-xl",
+        full: "sm:max-w-full",
+      },
     },
     defaultVariants: {
       side: "right",
+      size: "sm",
     },
   }
 )

68-71: Add aria-label to the close button.

The close button should have an aria-label for better accessibility.

-      <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
+      <SheetPrimitive.Close 
+        className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"
+        aria-label="Close sheet">
         <X className="h-4 w-4" />
         <span className="sr-only">Close</span>
       </SheetPrimitive.Close>
packages/web/src/app/onboard/components/orgCreateForm.tsx (3)

16-26: Consider adding more domain validation rules.

The domain validation could be enhanced to prevent common issues.

     domain: z.string()
         .min(2, { message: "Organization domain must be at least 3 characters long." })
         .max(20, { message: "Organization domain must be at most 20 characters long." })
-        .regex(/^[a-z][a-z-]*[a-z]$/, {
+        .regex(/^[a-z][a-z0-9-]*[a-z0-9]$/, {
             message: "Domain must start and end with a letter, and can only contain lowercase letters and dashes.",
           }),
+        .refine(
+          (value) => !value.includes('--'),
+          { message: "Domain cannot contain consecutive dashes" }
+        )
+        .refine(
+          (value) => !/^(xn--|sourcebot-)/.test(value),
+          { message: "Domain cannot start with reserved prefixes" }
+        ),

43-56: Add loading state during domain check.

The form submission doesn't show a loading state while checking the domain.

+    const [isSubmitting, setIsSubmitting] = useState(false);
 
     async function submitOrgInfoForm(data: OnboardingFormValues) {
+        setIsSubmitting(true);
         const res = await checkIfOrgDomainExists(data.domain);
+        setIsSubmitting(false);
         if (isServiceError(res)) {
             setErrorMessage("An error occurred while checking the domain. Please try clearing your cookies and trying again.");
             return;
         }

Then update the submit button:

-                        <Button type="submit">Create</Button>
+                        <Button type="submit" disabled={isSubmitting}>
+                            {isSubmitting ? "Checking..." : "Create"}
+                        </Button>

58-62: Add debouncing to domain updates.

The domain field updates immediately with every name change, which could cause performance issues with rapid typing.

+    const debounce = (fn: Function, ms = 300) => {
+        let timeoutId: ReturnType<typeof setTimeout>;
+        return function (this: any, ...args: any[]) {
+            clearTimeout(timeoutId);
+            timeoutId = setTimeout(() => fn.apply(this, args), ms);
+        };
+    };
+
+    const debouncedHandleNameChange = debounce((name: string) => {
+        const domain = name.toLowerCase().replace(/\s+/g, "-");
+        form.setValue("domain", domain);
+    });
+
     const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-        const name = e.target.value
-        const domain = name.toLowerCase().replace(/\s+/g, "-")
-        form.setValue("domain", domain)
+        debouncedHandleNameChange(e.target.value);
     }
packages/web/src/app/[domain]/components/navigationMenu.tsx (1)

95-105: Consider caching the trial status calculation.

The trial days calculation is performed on every render and could be optimized.

+    const getTrialDaysLeft = (nextBillingDate: number) => {
+        return Math.ceil((nextBillingDate * 1000 - Date.now()) / (1000 * 60 * 60 * 24));
+    };
+
     {!isServiceError(subscription) && subscription.status === "trialing" && (
         <Link href={`/${domain}/settings/billing`}>
             <div className="flex items-center gap-2 px-3 py-1.5 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-700 rounded-full text-yellow-700 dark:text-yellow-400 text-xs font-medium hover:bg-yellow-100 dark:hover:bg-yellow-900/30 transition-colors cursor-pointer">
                 <span className="inline-block w-2 h-2 bg-yellow-400 dark:bg-yellow-500 rounded-full"></span>
                 <span>
-                    {Math.ceil((subscription.nextBillingDate * 1000 - Date.now()) / (1000 * 60 * 60 * 24))} days left in
+                    {getTrialDaysLeft(subscription.nextBillingDate)} days left in
                     trial
                 </span>
             </div>
         </Link>
     )}
packages/db/prisma/migrations/20250212185343_add_stripe_customer_id_to_org/migration.sql (1)

1-2: Consider adding an index for stripeCustomerId.

Since this column will likely be used for lookups in Stripe-related operations, adding an index could improve query performance.

 -- AlterTable
 ALTER TABLE "Org" ADD COLUMN     "stripeCustomerId" TEXT;
+CREATE INDEX "Org_stripeCustomerId_idx" ON "Org"("stripeCustomerId");
packages/db/prisma/schema.prisma (2)

118-118: Add documentation, constraints, and index for the Stripe customer ID field.

Consider the following improvements for the stripeCustomerId field:

  1. Add documentation using triple-slash comments to explain the field's purpose
  2. Add a length constraint as Stripe customer IDs have a specific format
  3. Add an index to optimize queries by Stripe customer ID
+  /// The Stripe customer ID associated with this organization
+  /// @see https://stripe.com/docs/api/customers/object#customer_object-id
-  stripeCustomerId  String?
+  stripeCustomerId  String?    @db.VarChar(255)    @index

107-122: Consider adding additional models for complete Stripe billing support.

The current changes only track the Stripe customer ID. For a complete billing system, consider adding models to track:

  1. Subscriptions (status, plan, period)
  2. Payment methods
  3. Billing history

Example models to consider:

model OrgSubscription {
  id              Int      @id @default(autoincrement())
  org             Org      @relation(fields: [orgId], references: [id], onDelete: Cascade)
  orgId           Int      @unique
  stripeSubId     String   @db.VarChar(255)
  status          String   @db.VarChar(50)
  currentPeriodEnd DateTime
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
}

model OrgBillingHistory {
  id          Int      @id @default(autoincrement())
  org         Org      @relation(fields: [orgId], references: [id])
  orgId       Int
  amount      Int
  currency    String   @db.VarChar(3)
  status      String   @db.VarChar(50)
  invoiceId   String   @db.VarChar(255)
  createdAt   DateTime @default(now())
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 19780aa and b0cbcf0.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (41)
  • packages/backend/src/main.ts (1 hunks)
  • packages/db/prisma/migrations/20250212185343_add_stripe_customer_id_to_org/migration.sql (1 hunks)
  • packages/db/prisma/schema.prisma (1 hunks)
  • packages/web/package.json (5 hunks)
  • packages/web/src/actions.ts (6 hunks)
  • packages/web/src/app/[domain]/components/footer.tsx (1 hunks)
  • packages/web/src/app/[domain]/components/navigationMenu.tsx (4 hunks)
  • packages/web/src/app/[domain]/components/payWall/checkoutButton.tsx (1 hunks)
  • packages/web/src/app/[domain]/components/payWall/enterpriseContactUsButton.tsx (1 hunks)
  • packages/web/src/app/[domain]/components/payWall/paywallCard.tsx (1 hunks)
  • packages/web/src/app/[domain]/layout.tsx (2 hunks)
  • packages/web/src/app/[domain]/page.tsx (2 hunks)
  • packages/web/src/app/[domain]/settings/billing/manageSubscriptionButton.tsx (1 hunks)
  • packages/web/src/app/[domain]/settings/billing/page.tsx (1 hunks)
  • packages/web/src/app/[domain]/settings/components/inviteTable.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/components/inviteTableColumns.tsx (2 hunks)
  • packages/web/src/app/[domain]/settings/components/memberInviteForm.tsx (2 hunks)
  • packages/web/src/app/[domain]/settings/components/memberTable.tsx (1 hunks)
  • packages/web/src/app/[domain]/settings/components/memberTableColumns.tsx (2 hunks)
  • packages/web/src/app/[domain]/settings/components/sidebar-nav.tsx (1 hunks)
  • packages/web/src/app/[domain]/settings/layout.tsx (1 hunks)
  • packages/web/src/app/[domain]/settings/page.tsx (2 hunks)
  • packages/web/src/app/globals.css (2 hunks)
  • packages/web/src/app/layout.tsx (1 hunks)
  • packages/web/src/app/login/page.tsx (2 hunks)
  • packages/web/src/app/onboard/complete/page.tsx (1 hunks)
  • packages/web/src/app/onboard/components/errorPage.tsx (1 hunks)
  • packages/web/src/app/onboard/components/orgCreateForm.tsx (1 hunks)
  • packages/web/src/app/onboard/components/trialInfoCard.tsx (1 hunks)
  • packages/web/src/app/onboard/page.tsx (1 hunks)
  • packages/web/src/app/redeem/page.tsx (3 hunks)
  • packages/web/src/components/hooks/use-mobile.tsx (1 hunks)
  • packages/web/src/components/ui/button.tsx (1 hunks)
  • packages/web/src/components/ui/input.tsx (1 hunks)
  • packages/web/src/components/ui/sheet.tsx (1 hunks)
  • packages/web/src/components/ui/sidebar.tsx (1 hunks)
  • packages/web/src/lib/environment.ts (1 hunks)
  • packages/web/src/lib/errorCodes.ts (1 hunks)
  • packages/web/src/lib/serviceError.ts (1 hunks)
  • packages/web/src/lib/stripe.ts (1 hunks)
  • packages/web/tailwind.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/web/src/app/layout.tsx
  • packages/web/src/app/[domain]/settings/page.tsx
🔇 Additional comments (50)
packages/web/src/app/[domain]/settings/components/memberTable.tsx (3)

4-4: LGTM!

The import statement correctly reflects the updated export name and follows React component naming conventions.


6-11: LGTM!

The interface updates appropriately support the new member management functionality:

  • id and email fields enable member identification and removal
  • currentUserId prop enables conditional rendering of remove buttons

Also applies to: 13-16


31-39: LGTM!

The updated component structure improves UI organization and correctly implements the member table functionality.

packages/web/src/app/[domain]/settings/components/memberTableColumns.tsx (1)

3-18: LGTM!

The imports and type definition appropriately support the new member management functionality.

Also applies to: 20-25

packages/web/src/app/[domain]/settings/components/inviteTable.tsx (3)

5-5: LGTM!

The import statement for the toast hook is correctly added.


18-24: LGTM!

The toast hook is correctly used and the displayToast function provides a clean abstraction for showing notifications.


40-40: LGTM!

The displayToast function is correctly passed to inviteTableColumns.

packages/web/src/app/[domain]/settings/components/inviteTableColumns.tsx (2)

15-15: LGTM!

The function signature is correctly updated to accept the displayToast callback.


32-33: LGTM!

Using id as the column identifier is a good practice.

packages/web/src/app/onboard/page.tsx (3)

1-8: All imports look good.

No concerns for these initial imports and the "use client" directive.


9-12: Component initialization appears fine.

The function signature and state variable definitions are appropriate.


24-34: Conditional rendering logic is clear.

Rendering a TrialCard after successful org form submission is straightforward. Keep an eye on potential error states if orgCreateInfo is partially populated or if form submission fails.

packages/web/src/app/onboard/complete/page.tsx (5)

1-14: Imports and interface definition look fine.

No issues with the approach of defining your OnboardCompleteProps interface here.


27-36: Parameter checks are handled properly.

You correctly short-circuit and render ErrorPage if required search parameters are missing.


37-42: Stripe session validation is limited to "paid."

Stripe has additional payment statuses (like "requires_capture", "requires_payment_method", etc.). Confirm that "paid" covers all your success scenarios.


43-48: Organization creation error handling is good.

If the domain is already taken or an unexpected error occurs, isServiceError(res) gracefully handles it. Make sure your UI or logs clearly indicate to the user that the domain might be in use.


50-51: Redirection after completion is clear.

The final redirect logic is straightforward.

packages/web/src/actions.ts (11)

5-5: Import updates are valid.

No immediate concerns with these added imports from @/lib/serviceError, @sourcebot/db, etc.

Also applies to: 15-20


61-64: isAuthed function is concise and clear.

Acknowledged usage of auth() to check session presence.


66-90: Validate domain uniqueness or conflicts.

While createOrg depends on Prisma’s constraints to fail if the domain is taken, ensure the error path is surfaced or tested.


285-297: Blocking self-invites is a good safeguard.

Nice check preventing users from inviting themselves and returning a distinct error.


322-350: Check subscription status more thoroughly when redeeming invites.

Currently, seat increments happen if stripeCustomerId exists, but a subscription could be canceled or incomplete. Consider verifying subscription status or trial state.


416-462: setupInitialStripeCustomer uses test clocks.

Test clocks are valuable for CI and local testing but can lead to unexpected results in production. Ensure this logic is guarded by environment checks if it's not intended for live usage.


517-520: fetchStripeSession is straightforward.

Simple retrieval from Stripe is properly implemented.


522-543: getCustomerPortalSessionLink flow looks good.

Portal sessions are valid only if the customer has an active subscription. Ensure you handle or display a helpful message if they do not.


565-573: checkIfUserHasOrg is implemented properly.

No specific issues.


575-585: checkIfOrgDomainExists is straightforward.

Simple domain lookup.


586-643: removeMember logic matches redeemInvite approach.

Seating logic is consistent.

packages/web/src/components/ui/sidebar.tsx (1)

195-212: Validate mobile states before rendering in a sheet.
When isMobile is true, the sidebar is rendered using SheetContent. Ensuring that isMobile is derived consistently across client-side navigation prevents rendering mismatches. Also, verify that there's no hydration mismatch if server-side rendered markup differs from client logic.

packages/web/src/lib/errorCodes.ts (1)

8-14: LGTM! Error codes are well-defined.

The new error codes follow the existing pattern and cover essential error cases for the Stripe billing integration.

packages/web/src/components/ui/input.tsx (1)

5-5: Great improvements to the Input component!

The changes enhance the component in two ways:

  1. Using React.ComponentProps<"input"> provides complete type coverage by leveraging React's built-in input props.
  2. The responsive text sizing (text-base and md:text-sm) improves mobile-first design.

Also applies to: 11-11

packages/web/src/lib/environment.ts (1)

15-15: Verify the non-null assertion on AUTH_URL.

Adding a non-null assertion (!) could lead to runtime errors if AUTH_URL is not provided. Consider handling the null case gracefully or documenting why this assertion is safe.

packages/web/src/app/[domain]/settings/components/sidebar-nav.tsx (1)

9-14: LGTM! Props interface is well-defined.

The interface correctly extends HTML attributes and defines the required item structure.

packages/web/src/app/[domain]/settings/billing/manageSubscriptionButton.tsx (3)

1-9: LGTM!

All necessary imports are present and properly organized.


10-14: LGTM!

Hooks are properly initialized and follow React's rules of hooks.


31-36: LGTM!

Button implementation follows best practices with proper loading state handling and user feedback.

packages/web/src/app/onboard/components/errorPage.tsx (1)

1-7: LGTM!

All necessary imports are present and properly organized.

packages/web/src/app/[domain]/settings/layout.tsx (2)

1-9: LGTM!

Imports and metadata are properly organized and defined.


29-48: LGTM!

Layout implementation follows best practices with proper responsive design and semantic structure.

packages/web/src/app/[domain]/layout.tsx (1)

1-14: LGTM!

Imports and type definitions are properly organized and well-structured.

packages/web/src/components/ui/button.tsx (1)

8-8: LGTM! Button styling improvements enhance UI consistency.

The added classes improve button styling by:

  • Adding consistent spacing between elements with gap-2
  • Preventing pointer events on SVG icons
  • Maintaining consistent icon sizing with size-4
  • Preventing SVG shrinkage with shrink-0
packages/web/src/app/[domain]/settings/components/memberInviteForm.tsx (1)

48-49: LGTM! Layout improvements enhance form structure.

The added header and spacing classes improve the form's visual hierarchy.

packages/web/tailwind.config.ts (1)

13-19: LGTM! Comprehensive theme configuration enhances UI consistency.

The changes introduce:

  • Well-structured container configuration
  • Comprehensive sidebar theming using HSL variables
  • Consistent color system across components

Also applies to: 56-65

packages/web/src/lib/serviceError.ts (1)

88-94: LGTM! Clear domain existence error handling.

The error message for existing organization domain is clear and actionable.

packages/web/src/app/onboard/components/trialInfoCard.tsx (1)

26-26: Verify Stripe publishable key presence.

Add runtime check for the environment variable to prevent potential runtime errors.

-const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!)
+const stripePublishableKey = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
+if (!stripePublishableKey) {
+  throw new Error('Missing NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY')
+}
+const stripePromise = loadStripe(stripePublishableKey)
packages/web/src/components/ui/sheet.tsx (1)

18-31: LGTM! Well-structured overlay component.

The SheetOverlay component is well-implemented with proper ref forwarding and className composition.

packages/web/src/app/[domain]/page.tsx (1)

16-16: LGTM! Footer integration looks good.

The Footer component is properly integrated into the layout structure, maintaining the flex container's organization.

Also applies to: 113-113

packages/web/src/app/globals.css (1)

33-40: LGTM! Well-structured sidebar theming.

The sidebar CSS custom properties are well-organized with consistent naming and proper light/dark mode support.

Also applies to: 69-76

packages/web/package.json (2)

45-56: LGTM! Minor version updates for UI components.

The @radix-ui package updates are minor version bumps, maintaining compatibility.


67-68:

✅ Verification successful

Verify Stripe package versions and security implications.

Please ensure these Stripe package versions are compatible with your target Node.js version and check for any security advisories.

Also applies to: 118-118


🌐 Web query:

What are the latest versions of @stripe/react-stripe-js, @stripe/stripe-js, and stripe packages? Are there any known security vulnerabilities?

💡 Result:

Here are the latest versions and security statuses based on available information as of February 2025:

Latest Versions

@stripe/react-stripe-js
Latest: v3.1.1 (released ~2 months ago)

  • Requires React v16.8+
  • Supports TypeScript >=3.1[9][10]

@stripe/stripe-js
Latest: v5.6.0 (released ~16 days ago)

  • Minimum requirements: Node.js v12.16+, TypeScript v3.1+[8][2]

Stripe CLI
Latest patched version: v1.21.3 (fixes CVE GHSA-fv4g-gwpj-74gr)[6]


Security Vulnerabilities

Known Issues:

  • Stripe CLI path traversal vulnerability (GHSA-fv4g-gwpj-74gr)
    • Affected versions: 1.11.1 ≤ CLI <1.21.3
    • Fixed in v1.21.3 by removing unsafe plugin installation flags[6]

Clean Bills of Health:

  • @stripe/react-stripe-js: No detected vulnerabilities in recent versions (v2.x-v3.x)[3][10]
  • @stripe/stripe-js: No reported security issues[8][2]
  • Both packages pass Spectra Assure's malware/tampering checks[3][10]

Key Updates Since 2024:

Package Notable Changes
react-stripe-js Added React 19 support (v3.x)[7][10]
stripe-js TypeScript declarations now track latest Stripe API versions[5][8]
Stripe.js Core Runtime features unaffected by @stripe/stripe-js package updates[1][5]

For production use, always load Stripe.js directly from https://js.stripe.com to maintain PCI compliance[1].

Citations:


Stripe Package Versions and Security Verification

  • The versions in packages/web/package.json@stripe/react-stripe-js at v3.1.1 and @stripe/stripe-js at v5.6.0—are confirmed as the latest stable releases as of February 2025.
  • No known security vulnerabilities have been reported for these versions.
  • Verify that your target Node.js version meets the minimum requirements (Node.js v12.16+ for @stripe/stripe-js) and that your React and TypeScript versions are compatible.
  • For production environments, load Stripe.js directly from https://js.stripe.com to maintain PCI compliance.
  • These considerations also apply to the similar changes noted on line 118.

@msukkari msukkari merged commit 7c18712 into v3 Feb 13, 2025
1 check passed
brendan-kellam added a commit that referenced this pull request Apr 1, 2025
* SQL Database (#157)

* point zoekt to v3 branch

* bump zoekt version

* Add tenant ID concept into web app and backend (#160)

* hacked together a example of using zoekt grpc api

* provide tenant id to zoekt git indexer

* update zoekt version to point to multitenant branch

* pipe tenant id through header to zoekt

* remove incorrect submodule reference and settings typo

* update zoekt commit

* remove unused yarn script

* remove unused grpc client in web server

* remove unneeded deps and improve tenant id log

* pass tenant id when creating repo in db

* add mt yarn script

* add nocheckin comment to tenant id in v2 schema

---------

Co-authored-by: bkellam <bshizzle1234@gmail.com>

* bump zoekt version

* parallelize repo indexing (#163)

* hacked together a example of using zoekt grpc api

* provide tenant id to zoekt git indexer

* update zoekt version to point to multitenant branch

* pipe tenant id through header to zoekt

* remove incorrect submodule reference and settings typo

* update zoekt commit

* remove unused yarn script

* remove unused grpc client in web server

* remove unneeded deps and improve tenant id log

* pass tenant id when creating repo in db

* add mt yarn script

* add pol of bullmq into backend

* add better error handling and concurrency setting

* spin up redis instance in dockerfile

* cleanup transaction logic when adding repos to index queue

* add NEW index status fetch condition

* move bullmq deps to backend

---------

Co-authored-by: bkellam <bshizzle1234@gmail.com>

* Authentication (#164)

* Add Org table (#167)

* Move logout button & profile picture into settings dropdown (#172)

* Multi tenancy support in config syncer (#171)

* [wip] initial mt support in config syncer

* Move logout button & profile picture into settings dropdown (#172)

* update sync status properly and fix bug with multiple config in db case

* make config path required in single tenant mode

NOTE: deleting config/repos is currently not supported in multi tenancy case. Support for this will be added in a future PR

---------

Co-authored-by: Brendan Kellam <bshizzle1234@gmail.com>

* add tenant mode support in docker container:

* Organization switching & active org management (#173)

* updated syncedAt date after config sync:

* Migrate to postgres (#174)

* spin up postgres in docker container

* get initial pol of postgres db working in docker image

* spin up postgres server in dev case

* updated syncedAt date after config sync:

* remove unnecessary port expose in docker file

* Connection creation form (#175)

* fix issue with yarn dev startup

* init (#176)

* Add `@sourcebot/schemas` package (#177)

* Connection management (#178)

* add concept of secrets (#180)

* add @sourcebot/schemas package

* migrate things to use the schemas package

* Dockerfile support

* add secret table to schema

* Add concept of connection manager

* Rename Config->Connection

* Handle job failures

* Add join table between repo and connection

* nits

* create first version of crypto package

* add crypto package as deps to others

* forgot to add package changes

* add server action for adding and listing secrets, create test page for it

* add secrets page to nav menu

* add secret to config and support fetching it in backend

* reset secret form on successful submission

* add toast feedback for secrets form

* add instructions for adding encryption key to dev instructions

* add encryption key support in docker file

* add delete secret button

* fix nits from pr review

---------

Co-authored-by: bkellam <bshizzle1234@gmail.com>

* bump zoekt version

* enforce tenancy on search and repo listing endpoints (#181)

* enforce tenancy on search and repo listing

* remove orgId from request schemas

* adds garbage collection for repos (#182)

* refactor repo indexing logic into RepoManager

* wip cleanup stale repos

* add rest of gc logic

* set status to indexing properly

* add initial logic for staging environment

* try to move encryption key env decleration in docker file to fix build issues

* switch encryption key as build arg to se if that fixes build issues

* add deployment action for staging image

* try using mac github action runners instead

* switch to using arm64 runners on arm64 build

* change workflow names to fix trigger issue

* trigger staging actions to see if it works

* fix working directory typo and pray it doesnt push to prod

* checkout v3 when deploying staging

* try to change into the staging dir manuall

* dummy commit to trigger v3 workflows to test

* update staging deploy script to match new version in main

* reference proper image:tag in staging fly config

* update staging fly config to point to ghcr

* Connection management (#183)

* add invite system and google oauth provider (#185)

* add settings page with members list

* add invite to schema and basic create form

* add invite table

* add basic invite link copy button

* add auth invite accept case

* add non auth logic

* add google oauth provider

* fix reference to header component in connections

* add google logo to google oauth

* fix web build errors

* bump staging resources

* change staging cpu to perf

* add side bar nav in settings page

* improve styling of members page

* wip adding stripe checkout button

* wip onboarding flow

* add stripe subscription id to org

* save stripe session id and add manage subscription button in settings

* properly block access to pages if user isn't in an org

* wip add paywall

* Domain support

* Domain support (#188)

* Update Makefile to include crypto package when doing a make clean

* Add default for AUTH_URL in attempt to fix build

* attempt 2

* fix attempt #3: Do not require a encrpytion key at build time

* Fix generate script race condition

* Attempt #4

* add back paywall and also add support for incrememnting seat count on invite redemption

* prevent self invite

* action button styling in settings and toast on copy

* add ability to remove member from org

* move stripe product id to env var

* add await for blocking loop in backend

* add subscription info to billing page

* handle trial case in billing info page

* add trial duration indicator to nav bar

* check if domain starts or ends with dash

* remove unused no org component

* Generate AUTH_SECRET if not provided (#189)

* remove package lock file and fix prisma dep version

* revert dep version updates

* fix yarn.lock

* add auth and membership check to fetchSubscription

* properly handle invite redeem with no valid subscription case

* change back fetch subscription to not require org membership

* add back subscription check in invite redeem page

* Add stripe billing logic (#190)

* add side bar nav in settings page

* improve styling of members page

* wip adding stripe checkout button

* wip onboarding flow

* add stripe subscription id to org

* save stripe session id and add manage subscription button in settings

* properly block access to pages if user isn't in an org

* wip add paywall

* Domain support

* add back paywall and also add support for incrememnting seat count on invite redemption

* prevent self invite

* action button styling in settings and toast on copy

* add ability to remove member from org

* move stripe product id to env var

* add await for blocking loop in backend

* add subscription info to billing page

* handle trial case in billing info page

* add trial duration indicator to nav bar

* check if domain starts or ends with dash

* remove unused no org component

* remove package lock file and fix prisma dep version

* revert dep version updates

* fix yarn.lock

* add auth and membership check to fetchSubscription

* properly handle invite redeem with no valid subscription case

* change back fetch subscription to not require org membership

* add back subscription check in invite redeem page

---------

Co-authored-by: bkellam <bshizzle1234@gmail.com>

* fix nits

* remove providers check

* fix more nits

* change stripe init to be behind function

* fix publishible stripe key handling in docker container

* enforce owner perms (#191)

* add make owner logic, and owner perms for removal, invite, and manage subscription

* add change billing email card to billing settings

* enforce owner role in action level

* remove unused hover card component

* cleanup

* add back gitlab, gitea, and gerrit support (#184)

* add non github config definitions

* refactor github config compilation to seperate file

* add gitlab config compilation

* Connection management (#183)

* wip gitlab repo sync support

* fix gitlab zoekt metadata

* add gitea support

* add gerrit support

* Connection management (#183)

* add gerrit config compilation

* Connection management (#183)

---------

Co-authored-by: Brendan Kellam <bshizzle1234@gmail.com>

* fix apos usage in redeem page

* change csrf cookie to secure not host

* Credentials provider (#192)

* email password functionality

* feedback

* cleanup org's repos and shards if it's inactive (#194)

* add stripe subscription status and webhook

* add inactive org repo cleanup logic

* mark reactivated org connections for sync

* connections qol improvements (#195)

* add client side polling to connections list

* properly fetch repo image url

* add client polling to connection management page, and add ability to sync failed connections

* Fix build with suspense boundary

* improved fix

* add retries for 429 issues (#196)

* add connection compile retry and hard repo limit

* add more retry checks

* cleanup unused change

* address feedback

* fix build errors and add index concurrency env var

* add config upsert timeout env var

* Membership settings rework (#198)

* Add refined members list

* futher progress on members settings polish

* Remove old components

* feedback

* Magic links (#199)

* wip on magic link support

* Switch to nodemailer / resend for transactional mail

* Further cleanup

* Add stylized email using react-email

* fix

* Fix build

* db performance improvements and job resilience  (#200)

* replace upsert with seperate create many and raw update many calls

* add bulk repo status update and queue addition with priority

* add support for managed redis

* add note for changing raw sql on schema change

* remove non secret token options

* fix token examples in schema

* add better visualization for connection/repo errors and warnings (#201)

* replace upsert with seperate create many and raw update many calls

* add bulk repo status update and queue addition with priority

* add support for managed redis

* add note for changing raw sql on schema change

* add error package and use BackendException in connection manager

* handle connection failure display on web app

* add warning banner for not found orgs/repos/users

* add failure handling for gerrit

* add gitea notfound warning support

* add warning icon in connections list

* style nits

* add failed repo vis in connections list

* added retry failed repo index buttons

* move nav indicators to client with polling

* fix indicator flash issue and truncate large list results

* display error nav better

* truncate failed repo list in connection list item

* fix merge error

* fix merge bug

* add connection util file [wip]

* refactor notfound fetch logic and add missing error package to dockerfile

* move repeated logic to function and add zod schema for syncStatusMetadata

* add orgid unique constraint to repo

* revert repo compile update logic to upsert loop

* log upsert stats

* [temp] disable polling everywhere (#205)

* add health check endpoint

* Refined onboarding flow (#202)

* Redeem UX pass (#204)

* add log for health check

* fix new connection complete callback route

* add cpu split logic and only wait for postgres if we're going to connec to it

* Inline secret creation (#207)

* use docker scopes to try and improve caching

* Dummy change

* remove cpu split logic

* Add some instrumentation to web

* add posthog events on various user actions (#208)

* add page view event support

* add posthog events

* nit: remove unused import

* feedback

* fix merge error

* use staging posthog papik when building staging image

* fix other merge error and build warnings

* Add invite email (#209)

* wrap posthog provider in suspense to fix build error

* add grafana alloy config and setup (#210)

* add grafana alloy config and setup

* add basic repo prom metrics

* nits in dockerfile

* remove invalid characters when auto filling domain

* add login posthog events

* remove hard coded sourcebot.app references

* make repo garbage collection async (#211)

* add gc queue logic

* fix missing switch cases for gc status

* style org create form better with new staging domain

* change repo rm logic to be async

* simplify repo for inactive org query

* add grace period for garbage collecting repos

* make prom scrape interval 500ms

* fix typo in trial card

* onboarding tweaks

* rename some prom metrics and cleanup unused

* wipe existing repo if we've picked up a killed job to ensure good state

* Connections UX pass + query optimizations (#212)

* remove git & local schemas (#213)

* skip stripe checkout for trial + fix indexing in progress UI + additional schema validation (#214)

* add additional config validation

* wip bypass stripe checkout for trial

* fix stripe trial checkout bypass

* fix indexing in progress ui on home page

* add subscription checks, more schema validation, and fix issue with complete page

* dont display if no indexed repos

* fix skipping onboard complete check

* fix build error

* add back button in onboard connection creation flow

* Add back revision support (#215)

* fix build

* Fix bug with repository snapshot

* fix share links

* fix repo rm issue, 502 page, condition on test clock

* Make login and onboarding mobile friendly

* fix ordering of quick actions

* remove error msg dump on failed repo index job, and update indexedAt field

* Add mobile unsupported splash screne

* cherry pick fix for file links

* [Cherry Pick] Syntax reference guide (#169) (#216)

* Add .env to db gitignore

* fix case where we have repos but they're all failed for repo snapshot

* /settings/secrets page (#217)

* display domain properly in org create form

* Quick action tweaks (#218)

* revamp repo page (#220)

* wip repo table

* new repo page

* add indicator for when feedback is applied in repo page

* add repo button

* fetch connection data in one query

* fix styling

* fix (#219)

* remove / keyboard shortcut hint in search bar

* prevent switching to first page on data update and truncate long repo names in repo list

* General settings + cleanup (#221)

* General settings

* Add alert to org domain change

* First attempt at sending logs to grafana

* logs wip

* add alloy logs

* wip

* [temp] comment out loki for now

* update trial card content and add events for code host selection on onboard

* reduce scraping interval to 15s

* Add prometheus metric for pending repo indexing jobs

* switch magic link to invite code (#222)

* wip magic link codes

* pipe email to email provider properly

* remove magic link data cookie after sign in

* clean up unused imports

* dont remove cookie before we use it

* rm package-lock.json

* revert yarn files to v3 state

* switch email passing from cookie to search param

* add comment for settings dropdown auth update

* remove unused middleware file

* fix build error and warnings

* fix build error with useSearchParam not wrapped in suspense

* add sentry support to backend and webapp (#223)

* add sentry to web app

* set sentry environemnt from env var

* add sentry env replace logic in docker container

* wip add backend sentry

* add sentry to backend

* move dns to env var

* remove test exception

* Fix root domain issue on onboarding

* add setup sentry cli step to github action

* login to sentry

* fix sentry login in action

* Update grafana loki endpoint

* switch source map publish to runtime in entrypoint

* catch and rethrow simplegit exceptions

* alloy nits

* fix alloy

* backend logging (#224)

* revert grafana loki config

* fix login ui nits

* fix quick actions

* fix typo in secret creation

* fix private repo clone issue for gitlab

* add repo index timeout logic

* add posthog identify call after registeration

* various changes to add terms and security info (#225)

* add terms and security to footer

* add security card

* add demo card

* fix build error

* nit fix: center 'get in touch' on security card

* Dark theme improvements (#226)

* (fix) Fixed bug with gitlab and gitea not including hostname in the repoName

* Switch to using t3-env for env-var management (#230)

* Add missing env var

* fix build

* Centralize to using a single .env.development for development workflows (#231)

* Make billing optional (#232)

* Massage environment variables from strings to numbers (#234)

* Single tenancy & auth modes (#233)

* Add docs to this repo

* dummy change

* Declarative connection configuration (#235)

* fix build

* upgrade to next 14.2.25

* Improved database DX

* migrate to yarn v4

* Use origin from header for baseUrl of emails (instead of AUTH_URL). Also removed reference to hide scrollbars

* Remove SOURCEBOT_ENCRYPTION_KEY from build arg

* Fix issue with linking default user to org in single tenant + no-auth mode

* Fix fallback tokens (#242)

* add SECURITY_CARD_ENABLED flag

* Add repository weburl (#243)

* Random fixes and improvements (#244)

* add zoekt max wall time env var

* remove empty warning in docs

* fix reference in sh docs

* add connection manager upsert timeout env var

* Declarative connection cleanup + improvements (#245)

* change contact us footer in app to point to main contact form

* PostHog event pass (#246)

* fix typo

* Add sourcebot cloud environment prop to staging workflow

* Update generated files

* remove AUTH_URL since it unused and (likely) unnecessary

* Revert "remove AUTH_URL since it unused and (likely) unnecessary"

This reverts commit 1f4a5ae.

* cleanup GitHub action releases (#252)

* remove alloy, change auth defaul to disabled, add settings page in me dropdown

* enforce connection management perms to owner (#253)

* enforce conneciton management perms to owner

* fix formatting

* more formatting

* naming nits

* fix var name error

* change empty repo set copy if auth is disabled

* add CONTRIBUTING.md file

* hide settings in dropdown with auth isnt enabled

* handle case where gerrit weburl is just gitiles path

* Docs overhall (#251)

* remove nocheckin

* fix build error

* remove v3 trigger from deploy staging

* fix build errors round 2

* another error fix

---------

Co-authored-by: msukkari <michael.sukkarieh@mail.mcgill.ca>
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