DEV Community

Cover image for Remix SaaS kit v0.0.1 - QuickStart & Core Concepts
Alexandro Martinez
Alexandro Martinez

Posted on • Updated on

Remix SaaS kit v0.0.1 - QuickStart & Core Concepts

Thank you for trying out my Remix SaaS kit! I did not expect so many downloads, so I thought I should make this Quickstart Tutorial.

If you like what you got, consider giving it a 5-star on Gumroad :).

Introducing Remix SaaS kit v1.

Remix SaaS kit v1

1) Core Concepts

Before you follow the tutorial, I want you to know why I built it the way it is.

1.1) Tenant

I wanted to make an app where 1 email could have multiple accounts, like Notion.

A Tenant has its own:

  • Stripe Customer ID - Created at /register

  • Stripe Subscription ID - Created at /app/settings/subscription

  • Tenant Members - Created at /app/settings/members

  • Workspaces - Created at /app/settings/workspaces

1.2) Workspace

This depends on your SaaS implementation. For example, I have a SaaS where the Workspace is a Legal Company, and another one where each Workspace represents the Current Project. It's up to you.

A Workspace has its own:

  • Workspace Members

  • Links to other Workspaces

  • Employees

1.3) Link

You can delete this in your implementation, but it's there if you need it.

I wanted to make a SaaS where my users could like accounts with other users. For example, Workspace X from Tenant A, wants to share information with Workspace Z from Tenant B. On this implementation, there's a direction, where one Workspace is a Provider and the other one a Client.

A Link has its own:

  • Contracts

1.4) Contracts

You can delete this in your implementation, but it's there if you need it.

On every SaaS kit, I implemented a Contracts app, on which two linked workspaces can share 1 contract, and it belongs to both of them. Also, you can see how PDF upload/preview work.

A Contract references:

  • Linked Workspace Members

  • Current Workspace Employees

1.5) Employee

Simple CRUD demo.

1.6) TenantId, WorkspaceId, and LinkId fields

Since this boilerplate is designed to support multiple tenants, each with its own workspaces, you have to implement these fields (on your prisma calls) on every Entity you create, hence the Contracts and Employees demo. I plan to implement an automatic way of doing this, subscribe or follow me to stay tuned!


2) Quickstart Tutorial

Follow these steps to see what Remix SaaS kit can do.

2.1) Requirements:

2.2) Git

Open the downloaded project folder (I'm using VSCode), open a Terminal and run:

git init
git add .
git commit -am "initial"
Enter fullscreen mode Exit fullscreen mode

2.3) Environment file:

Rename the .env.example file to just .env.

.env file

Update the REMIX_SESSION_SECRET value to something secure (like abc123).

Set the REMIX_ADMIN_EMAIL with your email and something random for REMIX_ADMIN_PASSWORD.

Credentials

Get your Stripe Secret Key and set it to REMIX_STRIPE_SK.

Stripe Secret Key (use your own)

Open your Postmark Servers Dashboard, select or create your server, click on API Tokens and set it to REMIX_POSTMARK_SERVER_TOKEN.

Postmark Test Server (use your own)

(Optional) Open your Formspree Forms Dashboard, select or create your form, click on Integration, and set the Form's endpoint to REMIX_INTEGRATIONS_CONTACT_FORMSPREE.

Formspree Test Form (use your own)

Up to this point, you should have only 1 commit:

.env.example was renamed to .env, but .env is ignored by git

2.4) Database:

I highly recommend building your app first with SQLite, then moving to something like PostgreSQL/MySQL.

If you're not using SQLite, identify your database connection string format and set it to the DATABASE_URL environment variable.

PostgreSQL URL format

IMPORTANT: If you're using Supabase and you will host your app on a Serverles environment like Vercel or AWS Lambda, use the Connection Pooling String as specified here. As you can see, use the normal PostgreSQL connection string when creating, migrating, and seeding the database with Prisma, but use the Connection Pooling String when deploying to a Serverless environment.

Open the schema.prisma file, and set the corresponding database provider (sqlite, postgresql, mysql, sqlserver, mongodb, or cockroachdb).

Since I'm using Supabase, I set postgresql

Run the first migration and seed the database using this command:

npx prisma migrate dev --name init
Enter fullscreen mode Exit fullscreen mode

You should get the following output:

Prisma Migration and Seed

If for any reason, the migration was created successfully but did not seed the database, use the following command:

npx prisma db seed
Enter fullscreen mode Exit fullscreen mode

If you mess up the database, you can always reset it with Prisma, or drop the tables manually:

Drop Tables

DROP TABLES Script:

DROP TABLE IF EXISTS "_prisma_migrations";
DROP TABLE IF EXISTS "Joke";
DROP TABLE IF EXISTS "ContractMember";
DROP TABLE IF EXISTS "ContractActivity";
DROP TABLE IF EXISTS "ContractEmployee";
DROP TABLE IF EXISTS "Contract";
DROP TABLE IF EXISTS "Employee";
DROP TABLE IF EXISTS "Link";
DROP TABLE IF EXISTS "SubscriptionFeature";
DROP TABLE IF EXISTS "SubscriptionPrice";
DROP TABLE IF EXISTS "SubscriptionProduct";
DROP TABLE IF EXISTS "TenantUserInvitationWorkspace";
DROP TABLE IF EXISTS "TenantUserInvitation";
DROP TABLE IF EXISTS "WorkspaceUser";
DROP TABLE IF EXISTS "Workspace";
DROP TABLE IF EXISTS "TenantUser";
DROP TABLE IF EXISTS "Tenant";
DROP TABLE IF EXISTS "User";
Enter fullscreen mode Exit fullscreen mode

Up to this point, you should have 3 commits:

Files generated by the Prisma migration

2.4) App:

If you haven't already, install the dependencies:

npm install
Enter fullscreen mode Exit fullscreen mode

Run the application:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Open https://localhost:3000, you should see the landing page:

Dark mode landing page

Click on the Dark/Light mode Toggle:

Light mode landing page

Get rid of the <TopBanner /> component, or customize it if you're advertising something, like me (other SaaS kits).

TopBanner.tsx component (used on root.tsx)

Go to the /pricing page and click on Go to /admin/pricing.

NOTE: Before we persist the Prices to the database, you can play with the pricing by modifying the plans.server.ts file.

Warning Banner - prices are being loaded from a file, not from your database

Log in as your admin user. If successful, it will redirect you with a Session Cookie to /admin/pricing.

Here we can persist the prices to our database and to our Stripe account by clicking the orange button.

Admin: Pricing management (CREATE only, you cannot UPDATE nor DELETE)

NOTE: If you've persisted the prices to your DB and Stripe, but you want to make a change, you could manually DELETE the records on the following tables: "SubscriptionFeature", "SubscriptionPrice" and "SubscriptionProduct".

DELETE pricing script

Now that our prices exist, go to /register and create a sample account (with a real email to get the Welcome email).

Register page

You should get a welcome email.

Welcome email

You will be redirected to the Dashboard:

Dashboard

That's all you need to get started using the boilerplate. And of course, you could also follow the README.md file.

Early Access

Click here to get -50 off, for a limited time only.

Subscribe or follow me to stay tuned!


Feel free to comment below if you have any questions.

Oldest comments (2)

Collapse
 
iamluisj profile image
Luis Juarez

Hello! The kit is really cool, some great components implemented and overall a great example of the power of Remix.

A few things I found confusing:

  1. Here you use npm, but in the readme you use yarn. I had issues trying to install dependencies with npm so I switched to yarn and that seemed to work.
  2. Would be great if you can reduce the amount of required env "dependencies" - meaning that most environment variables should be blank if the feature is not being used. A great kit should let you run npm run dev right out of the box and see a working example. In this case, adding a stripe key, formspree and postmark info, I still had some issues getting it up and running. (note: I would recommend using a validator function as a flag that turns off features if missing the environment variable)
  3. Would love more info on the template, I'm still a bit lost how the tenants/workspaces tie together.

Again, really cool project, and neat components. I think a few tweaks could make this a great go to kit.

Collapse
 
alexandromtzg profile image
Alexandro Martinez

I’m glad you liked it! 😁

  1. It think you need Node >= 16 if you’re using npm. I have no problem on my environment, here’s a video with npm (I had to comment the app/utils/email.server.ts file, as you specify in your sencond point). Maybe you could tell me your node and npm versions to replicate this issue 🤔.

  2. Agree that it’s ugly when things are hard-coded or so dependent on a specific third party 😓; for now, you could find and delete all sendEmail(…) calls. Although, I think it kinda defeats the purpose of SaaS if you don’t start with Postmark/SendGrid/Supabase emails/etc…, since you need an email provider to recover your password, even if you’re just testing on a local environment with an SQLite database. Nevertheless I already finished a skeleton version on the private repo (which also deletes the Workspaces concept), will commit it this weekend, after most of these issues are resolved (only for paid users though).

  3. I’m being mentored by Chris Kluis. One of the things he tells me, is just this. Tenants and Workspaces are confusing, it shouldn’t be shown to the end user, it’s more of a Database layer to separate data. I’m working on this, but to give you an idea, a Tenant is an organization, and a Workspace could be a: Project, Department, Branch… let’s say it’s a Project. Now all your contracts depend on the Tenant AND Workspace your currently in. But yeah, I’m realizing it’s very confusing, I'll try my best to clarify the concept on the next release.

Thanks again your your comments!