Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
STRIPE_API_KEY: ${{ secrets.STRIPE_KEY }}
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
STRIPE_CUSTOMER_PORTAL_URL: https://billing.stripe.com/p/login/test_8wM8x17JN7DT4zC000
PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID: ${{ secrets.STRIPE_HOBBY_SUBSCRIPTION_PRICE_ID }}
PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID: ${{ secrets.STRIPE_PRO_SUBSCRIPTION_PRICE_ID }}
PAYMENTS_CREDITS_10_PLAN_ID: ${{ secrets.STRIPE_CREDITS_PRICE_ID }}
Expand Down
5 changes: 4 additions & 1 deletion opensaas-sh/app_diff/deletions
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
.env.client.example
.env.server.example
src/client/static/open-saas-banner-dark.png
src/client/static/open-saas-banner-light.png
src/landing-page/components/Hero.tsx
src/landing-page/contentSections.ts
src/payment/lemonSqueezy/checkoutUtils.ts
src/payment/lemonSqueezy/paymentDetails.ts
src/payment/lemonSqueezy/paymentProcessor.ts
src/payment/lemonSqueezy/userPaymentDetails.ts
src/payment/lemonSqueezy/webhook.ts
src/payment/lemonSqueezy/webhookPayload.ts
src/payment/webhook.ts
4,585 changes: 295 additions & 4,290 deletions opensaas-sh/app_diff/package-lock.json.diff

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion opensaas-sh/app_diff/public/piggy.js.diff
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@
+ api_host: 'https://us.i.posthog.com',
+ person_profiles: 'identified_only',
+})
\ No newline at end of file
15 changes: 8 additions & 7 deletions opensaas-sh/app_diff/src/analytics/stats.ts.diff
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
--- template/app/src/analytics/stats.ts
+++ opensaas-sh/app/src/analytics/stats.ts
@@ -2,11 +2,9 @@
import { type DailyStatsJob } from 'wasp/server/jobs';
import Stripe from 'stripe';
import { stripe } from '../payment/stripe/stripeClient';
@@ -1,12 +1,10 @@
-import { listOrders } from '@lemonsqueezy/lemonsqueezy.js';
import Stripe from 'stripe';
import { type DailyStats } from 'wasp/entities';
import { type DailyStatsJob } from 'wasp/server/jobs';
+import { SubscriptionStatus } from '../payment/plans';
import { stripeClient } from '../payment/stripe/stripeClient';
import { getDailyPageViews, getSources } from './providers/plausibleAnalyticsUtils';
-// import { getDailyPageViews, getSources } from './providers/googleAnalyticsUtils';
// import { getDailyPageViews, getSources } from './providers/googleAnalyticsUtils';
-import { paymentProcessor } from '../payment/paymentProcessor';
import { SubscriptionStatus } from '../payment/plans';
+// import { getDailyPageViews, getSources } from './providers/googleAnalyticsUtils';
-import { SubscriptionStatus } from '../payment/plans';

export type DailyStatsProps = { dailyStats?: DailyStats; weeklyStats?: DailyStats[]; isLoading?: boolean };

Expand Down
12 changes: 2 additions & 10 deletions opensaas-sh/app_diff/src/payment/paymentProcessor.ts.diff
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
--- template/app/src/payment/paymentProcessor.ts
+++ opensaas-sh/app/src/payment/paymentProcessor.ts
@@ -3,7 +3,6 @@
import type { MiddlewareConfigFn } from 'wasp/server';
import { PrismaClient } from '@prisma/client';
import { stripePaymentProcessor } from './stripe/paymentProcessor';
-import { lemonSqueezyPaymentProcessor } from './lemonSqueezy/paymentProcessor';

export interface CreateCheckoutSessionArgs {
userId: string;
@@ -24,9 +23,4 @@
@@ -26,9 +26,4 @@
webhookMiddlewareConfigFn: MiddlewareConfigFn;
}

-/**
- * Choose which payment processor you'd like to use, then delete the
- * Choose which payment processor you'd like to use, then delete the
- * other payment processor code that you're not using from `/src/payment`
- */
-// export const paymentProcessor: PaymentProcessor = lemonSqueezyPaymentProcessor;
Expand Down
15 changes: 0 additions & 15 deletions opensaas-sh/app_diff/src/payment/stripe/paymentDetails.ts.diff

This file was deleted.

35 changes: 28 additions & 7 deletions opensaas-sh/app_diff/src/payment/stripe/paymentProcessor.ts.diff
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
--- template/app/src/payment/stripe/paymentProcessor.ts
+++ opensaas-sh/app/src/payment/stripe/paymentProcessor.ts
@@ -20,7 +20,7 @@
id: userId
@@ -24,7 +24,7 @@
id: userId,
},
data: {
- paymentProcessorUserId: customer.id
+ stripeId: customer.id
}
})
if (!stripeSession.url) throw new Error('Error creating Stripe Checkout Session');
- paymentProcessorUserId: customer.id,
+ stripeId: customer.id,
},
});

@@ -51,17 +51,17 @@
id: args.userId,
},
select: {
- paymentProcessorUserId: true,
+ stripeId: true,
},
});

- if (!user.paymentProcessorUserId) {
+ if (!user.stripeId) {
return null;
}

const CLIENT_BASE_URL = process.env.WASP_WEB_CLIENT_URL || 'http://localhost:3000';
const session = await stripeClient.billingPortal.sessions.create({
- customer: user.paymentProcessorUserId,
+ customer: user.stripeId,
return_url: `${CLIENT_BASE_URL}/account`,
});

20 changes: 20 additions & 0 deletions opensaas-sh/app_diff/src/payment/stripe/userPaymentDetails.ts.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--- template/app/src/payment/stripe/userPaymentDetails.ts
+++ opensaas-sh/app/src/payment/stripe/userPaymentDetails.ts
@@ -26,7 +26,7 @@
) {
return userDelegate.update({
where: {
- paymentProcessorUserId: customerId,
+ stripeId: customerId,
},
data: {
datePaid,
@@ -48,7 +48,7 @@
) {
return userDelegate.update({
where: {
- paymentProcessorUserId: customerId,
+ stripeId: customerId,
},
data: {
subscriptionPlan: paymentPlanId,
75 changes: 53 additions & 22 deletions opensaas-sh/blog/public/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ If you find this template useful, consider giving us [a star on GitHub](https://
## What's inside?

The template itself is built on top of some very powerful tools and frameworks, including:
- [Wasp](https://wasp.sh) - a full-stack React, NodeJS, Prisma framework with superpowers- [Astro](https://starlight.astro.build/) - Astro's lightweight "Starlight" template for documentation and blog
- [Wasp](https://wasp.sh) - a full-stack React, NodeJS, Prisma framework with superpowers
- [Astro](https://starlight.astro.build/) - Astro's lightweight "Starlight" template for documentation and blog
- [Stripe](https://stripe.com) or [Lemon Squeezy](https://lemonsqueezy.com/) - for products and payments
- [Plausible](https://plausible.io) or [Google](https://analytics.google.com/) Analytics
- [OpenAI](https://openai.com) - OpenAI API integrated into the app or [Replicate](https://replicate.com/) (coming soon )
Expand Down Expand Up @@ -64,7 +65,7 @@ If you prefer video tutorials, you can watch this walkthrough below which will g
### Pre-requisites

You must have Node.js (and NPM) installed on your machine and available in `PATH` to use Wasp.
Your version of Node.js must be >= 20.
Your version of Node.js must be >= 22.12.

To switch easily between Node.js versions, we recommend using [nvm](https://github.com/nvm-sh/nvm).

Expand Down Expand Up @@ -128,7 +129,7 @@ Once Rosetta is installed, you should be able to run Wasp without any issues.

### Windows

In order to use Wasp on Windows, you need to install WSL2 (Windows Subsystem for Linux) and a Linux distribution of your choice. We recommend using Ubuntu.
In order to use Wasp on Windows, you need to install WSL2 (Windows Subsystem for Linux) and a Linux distribution of your choice. We recommend using Ubuntu.

**You can refer to this [article](https://wasp.sh/blog/2023/11/21/guide-windows-development-wasp-wsl) for a step by step guide to using Wasp in the WSL environment.** If you need further help, reach out to us on [Discord](https://discord.gg/rzdnErX).

Expand Down Expand Up @@ -173,7 +174,7 @@ curl -sSL https://get.wasp.sh/installer.sh | sh
</summary>
If you are using WSL2, make sure that your Wasp project is not on the Windows file system, <b>but instead on the Linux file system</b>. Otherwise, Wasp won't be able to detect file changes, due to this <a href='https://github.com/microsoft/WSL/issues/4739'>issue in WSL2</a>.
</details>
:::
:::

### Finalize Installation

Expand Down Expand Up @@ -874,7 +875,7 @@ To create a Google OAuth app and get your Google API keys, follow the instructio

To create a GitHub OAuth app and get your GitHub API keys, follow the instructions in [Wasp's GitHub Auth docs](https://wasp.sh/docs/auth/social-auth/github#3-creating-a-github-oauth-app).

To create a Discord OAuth app and get your Discord API keys, follow the instructions in [Wasp's Discord Auth docs](docs/auth/social-auth/google#3-creating-a-google-oauth-app)
To create a Discord OAuth app and get your Discord API keys, follow the instructions in [Wasp's Discord Auth docs](https://wasp.sh/docs/auth/social-auth/discord#3-creating-a-discord-app)

Again, Wasp will take care of the rest and update your AuthUI components accordingly.

Expand Down Expand Up @@ -1287,13 +1288,7 @@ export const stripe = new Stripe(process.env.STRIPE_KEY!, {
2. click on `+ add endpoint`
3. enter your endpoint url, which will be the url of your deployed server + `/payments-webhook`, e.g. `https://open-saas-wasp-sh-server.fly.dev/payments-webhook`

4. select the events you want to listen to. These should be the same events you're consuming in your webhook. For example, if you haven't added any additional events to the webhook and are using the defaults that came with this template, then you'll need to add:
<br/>- `account.updated`
<br/>- `checkout.session.completed`
<br/>- `customer.subscription.deleted`
<br/>- `customer.subscription.updated`
<br/>- `invoice.paid`
<br/>- `payment_intent.succeeded`
4. select the events you want to listen to. These should be the same events you're consuming in your webhook which you can find listed in [`src/payment/stripe/webhookPayload.ts`](https://github.com/wasp-lang/open-saas/blob/main/template/app/src/payment/stripe/webhookPayload.ts):

5. after that, go to the webhook you just created and `reveal` the new signing secret.
6. add this secret to your deployed server's `STRIPE_WEBHOOK_SECRET=` environment variable. <br/>If you've deployed to Fly.io, you can do that easily with the following command:
Expand Down Expand Up @@ -1620,7 +1615,7 @@ export const paymentProcessor: PaymentProcessor = lemonSqueezyPaymentProcessor;
At this point, you can delete:
- the unused payment processor code within the `/src/payment/<unused-provider>` directory,
- any unused environment variables from `.env.server` (they will be prefixed with the name of the provider your are not using):
- e.g. `STRIPE_API_KEY`, `STRIPE_CUSTOMER_PORTAL_URL`, `LEMONSQUEEZY_API_KEY`, `LEMONSQUEEZY_WEBHOOK_SECRET`
- e.g. `STRIPE_API_KEY`, `LEMONSQUEEZY_API_KEY`
- Make sure to also uninstall the unused dependencies:
- `npm uninstall @lemonsqueezy/lemonsqueezy.js`
- or
Expand Down Expand Up @@ -1666,22 +1661,21 @@ To create a test product, go to the test products url [https://dashboard.stripe.

### Create a Test Customer

To create a test customer, go to the test customers url [https://dashboard.stripe.com/test/customers](https://dashboard.stripe.com/test/customers).
You can create a test customer directly in the [Stripe Dashboard](https://dashboard.stripe.com/test/customers).

- Click on the `Add a customer` button and fill in the relevant information for your test customer.
:::note
When filling in the test customer email address, use an address you have access to and will use when logging into your SaaS app. This is important because the email address is used to identify the customer when creating a subscription and allows you to manage your test user's payments/subscriptions via the test customer portal
:::

Alternatively, OpenSasS will automatically create a test customer the first time a user starts a checkout session.
This customer is linked to the email address associated with your app's user.

### Set up the Customer Portal

Go to https://dashboard.stripe.com/test/settings/billing/portal in the Stripe Dashboard and activate and copy the `Customer portal link`. Paste it in your `.env.server` file:
You can set up your customer portal in your [Stripe Dashboard](https://dashboard.stripe.com/test/settings/billing/portal).

```ts title=".env.server"
STRIPE_CUSTOMER_PORTAL_URL=<your-test-customer-portal-link>
```
By default, OpenSaas generates a unique customer portal link for each user on the back end.
If you'd rather provide a permanent link to the customer portal, activate and copy the `Customer portal link`.

If you'd like to give users the ability to switch between different plans, e.g. upgrade from a hobby to a pro subscription, go down to the `Subscriptions` dropdown and select `customers can switch plans`.
If you'd like to give users the ability to switch between different plans, e.g., upgrade from a "Hobby" to a "Pro" subscription, go down to the `Subscriptions` dropdown and select `customers can switch plans`.

Then select the products you'd like them to be able to switch between.

Expand Down Expand Up @@ -2015,6 +2009,43 @@ The method you choose is up to you and will largely depend on the complexity of

---

# Vibe Coding with Open SaaS

If you're looking to use AI to help build (or "vibe code") your SaaS app, this guide is for you.

## Coding with AI, Open SaaS, & Wasp

Wasp is particularly well suited to coding with AI due to its central config file which gives LLMs context about the entire full-stack app, and its ability to manage boilerplate code so AI doesn't have to.

Regardless, there are still some shortcomings to using AI to code with Wasp, as well as a learning curve to using it effectively.

Luckily, we did the work for you and put together a bunch of resources to help you use Wasp & Open SaaS with AI as effectively as possible.

### AI Resources in the Template

The template comes with:
- A full set of rules files, `app/.cursor/rules`, to be used with Cursor or adapted to your coding tool of choice (Windsurf, Claude Code, etc.).
- A set of example prompts, `app/.cursor/example-prompts.md`, to help you get started.

### LLM-Friendly Documentation

We've also created a bunch of LLM-friendly documentation:
- [Open SaaS Docs - LLMs.txt](https://docs.opensaas.sh/llms.txt) - Links to the raw text docs.
- **[Open SaaS Docs - LLMs-full.txt](https://docs.opensaas.sh/llms-full.txt) - Complete docs as one text file.**
- Coming Soon! ~~[Wasp Docs - LLMs.txt](https://wasp.sh/llms.txt)~~ - Links to the raw text docs.
- Coming Soon! ~~[Wasp Docs - LLMs-full.txt](https://wasp.sh/llms-full.txt)~~ - Complete docs as one text file.

Add these to your AI-assisted IDE settings so you can easily reference them in your chat sessions with the LLM.
**In most cases, you'll want to pass the `llms-full.txt` to the LLM and ask it to help you with a specific task.**

### More AI-assisted Coding Learning Resources

Here's a list of articles and tutorials we've made:
- [3hr YouTube tutorial: Vibe Coding a Personal Finance App w/ Wasp & Cursor](https://www.youtube.com/watch?v=WYzEROo7reY)
- [Article: A Structured Workflow for "Vibe Coding" Full-Stack Apps](https://dev.to/wasp/a-structured-workflow-for-vibe-coding-full-stack-apps-352l)

---

# Admin Dashboard

This is a reference on how the Admin dashboard, available at `/admin`, is set up.
Expand Down
1 change: 1 addition & 0 deletions opensaas-sh/blog/public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
- [SEO](https://raw.githubusercontent.com/wasp-lang/open-saas/main/opensaas-sh/blog/src/content/docs/guides/seo.mdx)
- [Tests](https://raw.githubusercontent.com/wasp-lang/open-saas/main/opensaas-sh/blog/src/content/docs/guides/tests.md)
- [How (Not) to Update Your Open SaaS App](https://raw.githubusercontent.com/wasp-lang/open-saas/main/opensaas-sh/blog/src/content/docs/guides/updating-opensaas.md)
- [Vibe Coding with Open SaaS](https://raw.githubusercontent.com/wasp-lang/open-saas/main/opensaas-sh/blog/src/content/docs/guides/vibe-coding.mdx)
- [Admin Dashboard](https://raw.githubusercontent.com/wasp-lang/open-saas/main/opensaas-sh/blog/src/content/docs/general/admin-dashboard.mdx)
- [User Overview](https://raw.githubusercontent.com/wasp-lang/open-saas/main/opensaas-sh/blog/src/content/docs/general/user-overview.md)
19 changes: 9 additions & 10 deletions opensaas-sh/blog/src/content/docs/guides/payments-integration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const paymentProcessor: PaymentProcessor = lemonSqueezyPaymentProcessor;
At this point, you can delete:
- the unused payment processor code within the `/src/payment/<unused-provider>` directory,
- any unused environment variables from `.env.server` (they will be prefixed with the name of the provider your are not using):
- e.g. `STRIPE_API_KEY`, `STRIPE_CUSTOMER_PORTAL_URL`, `LEMONSQUEEZY_API_KEY`, `LEMONSQUEEZY_WEBHOOK_SECRET`
- e.g. `STRIPE_API_KEY`, `LEMONSQUEEZY_API_KEY`
- Make sure to also uninstall the unused dependencies:
- `npm uninstall @lemonsqueezy/lemonsqueezy.js`
- or
Expand Down Expand Up @@ -95,22 +95,21 @@ To create a test product, go to the test products url [https://dashboard.stripe.

### Create a Test Customer

To create a test customer, go to the test customers url [https://dashboard.stripe.com/test/customers](https://dashboard.stripe.com/test/customers).
You can create a test customer directly in the [Stripe Dashboard](https://dashboard.stripe.com/test/customers).

- Click on the `Add a customer` button and fill in the relevant information for your test customer.
:::note
When filling in the test customer email address, use an address you have access to and will use when logging into your SaaS app. This is important because the email address is used to identify the customer when creating a subscription and allows you to manage your test user's payments/subscriptions via the test customer portal
:::

Alternatively, OpenSasS will automatically create a test customer the first time a user starts a checkout session.
This customer is linked to the email address associated with your app's user.

### Set up the Customer Portal

Go to https://dashboard.stripe.com/test/settings/billing/portal in the Stripe Dashboard and activate and copy the `Customer portal link`. Paste it in your `.env.server` file:
You can set up your customer portal in your [Stripe Dashboard](https://dashboard.stripe.com/test/settings/billing/portal).

```ts title=".env.server"
STRIPE_CUSTOMER_PORTAL_URL=<your-test-customer-portal-link>
```
By default, OpenSaas generates a unique customer portal link for each user on the back end.
If you'd rather provide a permanent link to the customer portal, activate and copy the `Customer portal link`.

If you'd like to give users the ability to switch between different plans, e.g. upgrade from a hobby to a pro subscription, go down to the `Subscriptions` dropdown and select `customers can switch plans`.
If you'd like to give users the ability to switch between different plans, e.g., upgrade from a "Hobby" to a "Pro" subscription, go down to the `Subscriptions` dropdown and select `customers can switch plans`.

<Image src={switchPlans} alt="switch plans" loading="lazy" />

Expand Down
2 changes: 0 additions & 2 deletions template/app/.env.server.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
STRIPE_API_KEY=sk_test_...
# After downloading starting the stripe cli (https://stripe.com/docs/stripe-cli) with `stripe listen --forward-to localhost:3001/payments-webhook` it will output your signing secret
STRIPE_WEBHOOK_SECRET=whsec_...
# You can find your Stripe customer portal URL in the Stripe Dashboard under the 'Customer Portal' settings.
STRIPE_CUSTOMER_PORTAL_URL=https://billing.stripe.com/...

# For testing, create a new store in test mode on https://lemonsqueezy.com
LEMONSQUEEZY_API_KEY=eyJ...
Expand Down
6 changes: 3 additions & 3 deletions template/app/main.wasp
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,10 @@ page PricingPage {
component: import PricingPage from "@src/payment/PricingPage"
}

route CheckoutRoute { path: "/checkout", to: CheckoutPage }
page CheckoutPage {
route CheckoutResultRoute { path: "/checkout", to: CheckoutResultPage }
page CheckoutResultPage {
authRequired: true,
component: import Checkout from "@src/payment/CheckoutPage"
component: import CheckoutResultPage from "@src/payment/CheckoutResultPage"
}

query getCustomerPortalUrl {
Expand Down
Loading