Wayne
Wayneβ€’6mo ago

Convex SaaS Starter Template

https://www.convex.dev/templates/convex-saas Features - 🧩 Convex: A complete, reactive, typesafe backend with authentication and file storage. - ⚑ Vite: Next-Gen Frontend Tooling. - πŸ›οΈ Stripe: Subscription Plans, Customer Portal, and more. - πŸ”‘ Authentication: Email Code and Social Logins. - 🎨 TailwindCSS: Utility-First CSS Framework. - πŸ“ ShadCN: Composable React components. - πŸŒ™ Easy Theming: Switch between Light and Dark modes with ease. - πŸ—ΊοΈ TanStack Router: Simple Route Definitions. - πŸ“§ Resend: Email for Developers. - πŸ’Œ React Email: Customizable Emails with React. - πŸ“‹ Conform: Type-Safe Form Validation based on Web Fundamentals. - πŸ“₯ File Uploads: Profile Picture Uploads with Convex. - 🌐 I18N: Internationalization for your App. - 🧰 TanStack Development Tools: Enhanced Development Experience. - πŸ’… Modern UI: Carefully crafted UI with a Modern Design System. - πŸ• Custom Pages: Landing, Onboarding, Dashboard and Admin Pages. - πŸ“± Responsive: Works on all devices, from Mobile to Desktop. This was built off of the open source Remix SaaS from Daniel Kanem
No description
19 Replies
hrutik_k
hrutik_kβ€’6mo ago
dope πŸ”₯
sam
samβ€’6mo ago
Brilliant! Saved my day. Thanks for the ship! πŸ™ŒπŸΎ
ampp
amppβ€’6mo ago
It's nice to see the newer eslint file.. i keep wondering if we are crazy for running eslint 9.8 πŸ˜…. its mostly working... if you don't sneeze
David Alonso
David Alonsoβ€’5mo ago
Hey @Wayne , it would be appreciated to have some more elaborate docs on how to set up the stripe dashboard to get everything to work. I assume we have to manually create these plans, but I'm not sure if the nested stripeIds are priceIds and the outer one is a productId?
No description
erquhart
erquhartβ€’5mo ago
@David Alonso run the init convex action to seed the database and create the entities in Stripe. @Wayne pull request here: https://github.com/waynesutton/convex-saas/pull/3
David Alonso
David Alonsoβ€’5mo ago
damn wish I would have known yesterday I was testing one of the products i manually created and Stripe doesn't let me archive it, is there a way to not make it bail when there's an archived product? also, I assume this only creates stripe entities in test mode which we cna copy into live mode later? nvm, found the line and commented it out, why was that there?
erquhart
erquhartβ€’5mo ago
It creates entities on whatever stripe account you give it keys for. You can adapt the init script to create your actual products, and give it production stripe credentials when ready. It's there so the init script doesn't run more than once for a given set of stripe credentials. The starter automatically runs it with the dev command for easy setup.
jamwt
jamwtβ€’5mo ago
@erquhart just something to throw in the mix, we're likely going to be introducing some sort of onLoad mutation or something that every component (including the app) can register. this mutation would be called every time a deployment happens, or the deployment restarts, etc. it has a chance to "set up" the deployment or the component state or whatever, or run migrations, and so on. this is starting to be a pretty common need. it can schedule background work or kick off whatever background machinery/workflow should be running inside the deployment
erquhart
erquhartβ€’5mo ago
That will be super helpful
jamwt
jamwtβ€’5mo ago
yeah, our team has needed this like a million times dogfooding ftw
David Alonso
David Alonsoβ€’5mo ago
how can I have the starter seed the production database? cause convex dev won't I guess? I wanna be able to run the init script in the prod environment
erquhart
erquhartβ€’5mo ago
You can run the init function like any other convex function, dash or cli Conditional logic based on env is a code smell but probably the simplest approach for this.
ampp
amppβ€’5mo ago
this sounds like a precursor to dynamic table creation. πŸ˜…
David Alonso
David Alonsoβ€’5mo ago
I'm confused as to why this shows up like this given the lines of code below:
products: seededProducts.filter(
({ product }) => product !== PLANS.FREE
),
products: seededProducts.filter(
({ product }) => product !== PLANS.FREE
),
No description
David Alonso
David Alonsoβ€’5mo ago
the intended behavior is to only show paid plans right? Switching to free should be done by cancelling
erquhart
erquhartβ€’5mo ago
Is this the UI from stripe or your dashboard
David Alonso
David Alonsoβ€’5mo ago
from stripe
erquhart
erquhartβ€’5mo ago
Ah, actually, that's a miss from the port The original starter used the values of those enums, eg., "free", as the product id in stripe, because you can provide your own id for those (but not subscriptions or prices). For consistency and durability I decoupled the stripe id from the plan name, hence plan.key in the convex schema. All that to say, the id will never equal PLANS.FREE, need to compare to the actual id of the free plan in that filter.

Did you find this page helpful?