| 0:00 |
In this video, I’m going to walk you through how to set up a full stack SaaS application using NextJS and Supabase. |
| 0:07 |
I designed this project to be a complete overview of Supabase and an ideal starting point |
| 0:13 |
for anyone who wants to build and launch a SaaS application as quickly as possible. |
| 0:19 |
Here’s a quick demo of the finished product. It’s going to be a task management application. First, you’ll have to log in. |
| 0:27 |
And then on the dashboard, you can see all the tasks you’ve |
| 0:32 |
created. And you can click here to create a new task. It also has a special AI feature to assign a label |
| 0:40 |
automatically, depending on the task description. Once you’ve created a task, you can also click to go in |
| 0:48 |
and edit it. You can change the label, change any of the fields, and you can also upload an image to it. |
| 0:57 |
The app also has authentication, so when you log in, you can only see your own task. And you can go to your profile |
| 1:04 |
and you can see how many tasks you’ve created. There’s also a monthly subscription that you |
| 1:09 |
can use to upgrade your account. And the payments are implemented with Stripe, so if a user |
| 1:15 |
is signed up, they can click on this page to update or to cancel their subscription. As you can see, it’s quite a simple project, but it |
| 1:23 |
uses all the fundamental building blocks that nearly every single SaaS application will need to have. |
| 1:29 |
Things like authentication, compute, and data storage. We will need to use a tech stack that will let us do all of those things. |
| 1:36 |
There’s actually quite a few viable options here. I ended up going with NextJS and Supabase. I like the feature |
| 1:42 |
set that it offers, and I think that it strikes a good balance between simplicity and capability. |
| 1:49 |
The GitHub link for this entire project will be available in the video description. You can go there |
| 1:54 |
to browse the code or to clone the entire project. Now, this video isn’t exactly a coding tutorial, because each |
| 2:00 |
of the features here could probably be its own video. Instead, I’m going to focus on helping you understand |
| 2:06 |
how all of the pieces fit together, and I’m going to show you how to set up this project on your own machine, so that you can |
| 2:13 |
start building things with it right away. By the end of this video, you’ll have a good understanding |
| 2:19 |
of how Supabase works, you’ll learn four of its core features, and you’ll also have the |
| 2:25 |
actual project up and running on your machine. I’ve prepared this video assuming that you’re at |
| 2:31 |
least a mid-level developer, and here are some of the technologies we’ll be working with. If you aren’t familiar with them, then I’ll still |
| 2:38 |
try to make it as accessible as I can, but it just might be a little bit hard to follow. First, let’s start with a high-level overview of the whole project. |
| 2:46 |
These are the features that we want our app to have. They include task management, image attachments, automatic |
| 2:53 |
AI labeling for our tasks, and the ability to sell premium subscription plans to our users. |
| 2:59 |
It’s a pretty standard set of features for an app, but the reason I chose these is that behind |
| 3:04 |
each of these features, there’s a really important concept that I want to show you. So, having them all in one project is a great way |
| 3:12 |
to learn how to apply all of them at once. Now, let’s take a quick look at the architecture |
| 3:18 |
for this project. Here is a simplified diagram. For the backend, we’ll be using Supabase. Supabase describes itself as an open-source Firebase alternative, |
| 3:27 |
and if you don’t know what that is, you can sort of think of it as a lightweight cloud platform. |
| 3:33 |
It gives us almost everything we need for this app right out of the box and in one place. The database is going to be a PostgreSQL database, |
| 3:41 |
and the storage system is pretty similar to something like Amazon S3 or Firestore. |
| 3:47 |
For our backend compute, we can also create edge functions using TypeScript. And there’s also an inbuilt authentication system that |
| 3:54 |
integrates really well with all of these features, but also with third-party providers like Google, OAuth. |
| 4:00 |
The front end is going to be a fully static NextJS app. You’ll have a client library that will talk to Supabase directly. |
| 4:07 |
On top of that, we will also need a couple of third-party services to round out our feature set. |
| 4:13 |
We will need a Google Cloud account if we want users to be able to sign in with Google. For our backend feature, we can actually use any LLM here. |
| 4:21 |
And I’m just going to use OpenAI. And finally, we’ll use Stripe for our payments system. Now, how does this all get hosted, and how much will it cost? |
| 4:30 |
Well, you basically have a few different options with Supabase. The easiest option is to use their cloud service. |
| 4:37 |
This is really simple to set up, and it’s probably the best option if you want to get started as soon as possible. It comes with a free tier, which works perfectly fine for this project. |
| 4:46 |
And in fact, that is what we’ll be using. The next tier up is $25 a month, and it gives you a lot more of everything. |
| 4:53 |
That being said, Supabase is also completely open source. So another option is that you can host it yourself |
| 5:00 |
or deploy it to a cloud provider like AWS or GCP. But I think that’s going to be quite complex to manage, |
| 5:06 |
and I don’t really recommend doing that. It’s just good to know that it is an option. Okay, so now that we’ve gone over all the high-level stuff, let’s |
| 5:14 |
look at our plan for how we’re going to set up the project. We will need to set up five separate things to get this all working. |
| 5:20 |
We’ll start by just downloading the code from GitHub and then creating a project on the Supabase cloud. |
| 5:26 |
Then we’ll go and set up the rest of the dependencies first. Google OAuth, OpenAI, and Stripe. |
| 5:32 |
And then we’ll have all the API keys we need to go back to our project and actually finish setting it up. |
| 5:38 |
Here’s a checklist of the steps that we are going to take. And throughout this video, we’ll go down the |
| 5:43 |
list and we’ll tick them off one by one. Let’s start off by cloning the project. By the way, all the links you need for this video |
| 5:49 |
are going to be in the video description. Once you’ve cloned the project, open the project in your terminal and run npm install. |
| 5:56 |
This should finish successfully, but there might be a few |
| 6:01 |
warnings because things are always getting deprecated. We will also need to create two local .env |
| 6:09 |
files to store our environment variables. I’ve actually created an example.env file for you here. |
| 6:16 |
So if you’re on a Unix system, you can just run this command to create copies from that. And if you open the project in VSCode, you’ll be able to see them here. |
| 6:29 |
So here is the example file, and here are the two files I’ve just created. And they have to be named exactly this way because that’s |
| 6:37 |
where our project is going to be looking for them. Now here are some of the environment variables that we’ll need to fill in. |
| 6:43 |
We’ll come back to this later once we actually have them. That’s all the setup we have to do for our project code at the moment. |
| 6:50 |
But if you try to run it now, it won’t work because we haven’t set up any of the backend yet. But if you do want to see the front end of the project |
| 6:58 |
on its own and play around with it, then I actually have an earlier commit where it’s just |
| 7:04 |
using placeholders for all of the backend logic. So if you go to the GitHub repo and click on the commits |
| 7:10 |
tab, you can scroll down all the way to the bottom. And there’s this commit here that says front end boilerplate. |
| 7:18 |
So you can copy this commit hash, and then you can run this command in your project folder to check out that specific commit. |
| 7:27 |
So if you use that command to roll it back to that commit, you should be able to run npm run dev, |
| 7:33 |
and it’ll start a local version of the site. And this will run a version of the site where you just have the |
| 7:39 |
front end and all of the backend integration is stripped out. You can still click around and play around with the UI, but it won’t do anything. |
| 7:47 |
And you’ll find that any of the buttons or the interactions will basically just console log a to-do statement for it to be implemented. |
| 7:54 |
But now, back to this project, we will want to use the latest commit. So if you did check out the older commit, then |
| 8:00 |
please use this command to revert it back. Let’s move on to the next step, which is to create an actual Supabase project. |
| 8:06 |
Go to Supabase.com and create or log in with your account. In your dashboard, click create new project. |
| 8:15 |
You might also have to create an organization first, but I already have one here. |
| 8:21 |
Fill in your project name and generate a secure password for your database. You’ll also want to copy the database password |
| 8:28 |
as well, because you’re going to need it later when we set up the Supabase CLI. |
| 8:34 |
And finally, choose a region that’s close to you or your customers. Then go ahead and create the project. |
| 8:42 |
This will take a few minutes to set up, but while you wait, it does show you your API keys and some important |
| 8:48 |
information that we will need in the next step. Or if your project already finished setting |
| 8:53 |
up, then it will look something like this. On the toolbar on the left, go over to project settings. |
| 9:00 |
You’ll find some really useful things on this page. For example, you can look at what compute your project is configured to use. |
| 9:07 |
You can also check out how much storage disk you’re using up already. And also extra options like adding custom domain names. |
| 9:16 |
But for now, what we need is under this API configuration tab. Here you’ll find the project URL and two API keys. |
| 9:26 |
One is a public key, so this is for the Supabase client. This one is okay to be revealed, because this is the one that’s |
| 9:33 |
usually embedded with the front end client anyways. It’s going to be what your website uses to call the Supabase backend. |
| 9:41 |
The other one is a secret key. This is useful for doing backend server-side operations. This one you definitely do not want to reveal. |
| 9:49 |
So now we’re going to copy the URL and the public key back to our project. And then back in your project, go to your .env.local |
| 9:57 |
file, or create one if you didn’t do it already. And we’ll only need these two things, we actually don’t |
| 10:02 |
need these other keys, so we can delete those. And go ahead and paste your project URL and your public key. |
| 10:10 |
Now to work with Supabase from our local environment, we’re going to want to use the Supabase CLI. |
| 10:16 |
So just search for Supabase CLI on Google, and you should see the official documentation pop up. |
| 10:22 |
Then scroll down and follow the instructions for your specific platform to install the CLI. |
| 10:29 |
Then you can verify the installation using this command. For this video I’m using Supabase version 2, so if you’re |
| 10:35 |
using a different major version, then keep in mind that some of the CLI commands may be different. |
| 10:41 |
Now back in our development environment, you’d normally have to run this command to initialize Supabase |
| 10:46 |
to add it to a project that doesn’t have it yet. But for our project, I actually initialized Supabase |
| 10:51 |
earlier, and you can tell because there’s a Supabase folder with a config file. So we don’t have to run the command again for this one. |
| 10:59 |
We will need to run this command to link your local project with the remote Supabase project. |
| 11:05 |
Don’t forget to replace the PROJECT REF variable with your own one. Your project reference is basically the random ID part of your URL. |
| 11:14 |
When you run this command, it’s going to ask you to enter |
| 11:19 |
your database password from when you created the project. So go ahead and do that as well. |
| 11:27 |
Now that should work successfully, but it might throw a warning about the local config being different from the linked project. |
| 11:34 |
But I wouldn’t worry about that for now. Then to test if everything is set up correctly, you can run this command. |
| 11:40 |
You should see a list of projects, and you should also see a dot next to the one that is linked. |
| 11:47 |
Alright, so at this point we’ve downloaded the project code, and we’ve set up the Supabase project itself. Let’s move on to the next step. |
| 11:54 |
Next, we’re going to set up Google Cloud so that we can let our users log in with a Google account. Supabase actually has a lot of different options |
| 12:01 |
for signing in, but I prefer to just use a third party integration like Google, because it’s |
| 12:07 |
both easier for us to maintain, and it’s also easier for our customers as well, because they |
| 12:12 |
don’t have to sign up for a separate account. First, head over to the Google Cloud console, and then either |
| 12:18 |
log in or create an account if you don’t already have one. And if this is your first time using Google Cloud, |
| 12:25 |
you will also have to create a new project. So I’ve created a project here for this SaaS application. |
| 12:32 |
Now you might also need to attach a credit card to this account, but the OAuth pricing |
| 12:37 |
is free for up to 50,000 monthly active users, so you probably won’t get charged. |
| 12:43 |
So once you’re on this page, go to the search bar at the top and type in “Credentials”, and |
| 12:48 |
select “Credentials” from “API and Services”. Now on this page, click here to create credentials, and select “OAuth client ID”. |
| 12:58 |
For the application type, choose “web application”, and then type in a name for it here. |
| 13:05 |
Now we also have to add the authorized JavaScript origins and the authorized redirect URIs. |
| 13:13 |
For the authorized origin, put your Supabase project URL, and you can also put localhost so that |
| 13:18 |
we can test it from our development environment. And for the redirect, put in this URL. |
| 13:24 |
This is actually provided to us by Supabase. If you go to authentication, then to providers, |
| 13:30 |
and then expand the Google tab, you will see the callback URL here for us to copy. |
| 13:36 |
So let’s go back to the project and put that in. So now your settings should look something like this, |
| 13:42 |
and then you can go ahead and click “create”. And when that’s done, you should see this little pop-up |
| 13:48 |
with your client ID and your client secret. So go back to your Supabase dashboard, go to authentication, |
| 13:56 |
and then providers, and then open the Google tab, and enable “sign in for Google”. |
| 14:03 |
And then just paste the client ID and the secret from the previous step, and click “save”. |
| 14:09 |
While we’re here, you can also check out all the other authentication providers available, in case you want to use them. |
| 14:16 |
And just an interesting note, I’ve also enabled email as a provider, and I think that’s the default for a new Supabase project anyways. |
| 14:23 |
But for testing purposes, I actually disabled this “confirm email” feature, because it |
| 14:28 |
makes it easier for me to create test users. Okay, so now you’re done with auth, and your Supabase project |
| 14:34 |
should be wired up to let users log in with Google. Next, we’re also going to need an OpenAI API key. |
| 14:41 |
We’re going to be using this for our back-end feature, where we automatically assign |
| 14:46 |
labels to a task, based on its description. Now, this API is pay-per-use, but the pricing is quite |
| 14:53 |
cheap, and our usage is going to be very low. If you don’t have an OpenAI account, then go to platform.OpenAI.com to create it. |
| 15:02 |
Log into your account, and then open the search bar, and search for “API keys”. |
| 15:08 |
And then you can click up here to create a new API key for your project. So go ahead and create that, and then copy the secret key. |
| 15:15 |
Then, back in your project terminal, run the Supabase-cli command to set the OpenAI key as a back-end secret. |
| 15:23 |
The project will be using this later on in our server-side edge functions. The final dependency we need for this project is Stripe, and we’re |
| 15:33 |
going to use this to process payments for our customers. So, back in our app, we limit users to only creating 100 tasks per month. |
| 15:43 |
And when they upgrade to Premium, the limit gets raised to 10,000. Now, this is probably not the best business model |
| 15:50 |
for this app, but the point is just to show you how to implement this at a technical level. Compared to our other dependencies, Stripe is a little bit more complex to set up. |
| 16:00 |
But I’m going to try to keep this as simple as possible. There are three main steps we need to go through. |
| 16:06 |
First, we want to create an account and set up the Stripe CLI. And then we’ll have to create a product, which |
| 16:11 |
is basically the subscription for our app. And finally, we’ll need to set up webhooks so that |
| 16:17 |
Stripe can tell our Supabase server whenever there’s an update with our customers’ payments. |
| 16:23 |
If you don’t have a Stripe account yet, then go to stripe.com and create one. Once you’re signed in, you should be on this dashboard. |
| 16:31 |
Just go to the top and make sure that you enable test mode. This will basically let us test the whole integration |
| 16:38 |
without using real money or credit cards. Our Stripe account will also have a secret API key. |
| 16:45 |
So to find it, just go into the search box and type in “API key” and then go to “developers |
| 16:50 |
API key.” And take note of the secret key here, because we’re going to need this for later. |
| 16:56 |
Next, we’ll need to install the Stripe CLI. So just search for Stripe CLI on Google and it |
| 17:01 |
should link you to the official documentation. And if you scroll down, you’ll see different tabs depending |
| 17:07 |
on which platform you want to see the command for. Once you’ve installed it, then run this command in |
| 17:12 |
your terminal to log in with your Stripe account. Next, let’s use the Stripe CLI to create a new product and a price. |
| 17:20 |
In Stripe, products and prices are two distinct object types. And a product can have multiple different prices, but |
| 17:28 |
every price must be associated with a product. Now, to create the products and the prices, we can go to our Stripe |
| 17:35 |
dashboard and then click to create them through there. But we can also do it with a command in the CLI, which is a little bit faster. |
| 17:45 |
So that’s what I’m going to do for this project. So if you go back to the project and then you open the README file, scroll all the way down until |
| 17:51 |
you see the part that says Stripe setup. And there’s a couple of commands that you can just copy and paste into your terminal |
| 17:59 |
to create the product via the CLI directly. This command will create both a price and a product for us together. |
| 18:06 |
It creates a $10 monthly subscription for a new product called Taskmaster Premium with a 14-day trial. |
| 18:14 |
So go ahead and run that in your project terminal. And when it’s done, you should see an output object like this. |
| 18:22 |
And we’re going to want to take note of the price ID because we will need that for later. Next, we’ll also need to run another command to set up the customer portal. |
| 18:32 |
This is going to set up a page that customers can go to to either update or cancel their subscriptions. |
| 18:39 |
Just make sure that before you run this command to replace the URLs with your own Supabase URLs. |
| 18:45 |
And in this project, I actually haven’t created the privacy or the terms of service pages. So these links will probably just bounce back to the homepage. |
| 18:54 |
So that’s something you can add if you want. And to finish our Stripe setup, we will need to add a webhook. |
| 19:03 |
A webhook is a URL endpoint that we provide that Stripe can send events and notifications to. |
| 19:09 |
And it will use this to tell us about things like successful checkouts and subscription cancellations. |
| 19:15 |
And then we’ll use that information to update our database. So go back to your Stripe dashboard and then search for webhooks. |
| 19:23 |
And then go to Developers / Webhooks. And here, click add endpoint. |
| 19:29 |
Our webhook endpoint is going to look something like this. We will implement this later as an edge function. |
| 19:35 |
Just make sure to update the project ID to your actual Supabase project URL. |
| 19:41 |
And then enter it here as your endpoint. |
| 19:47 |
Next, you have to select which events for it to listen to. |
| 19:53 |
These are the four events that you need to select. These events will give us everything we need to build the |
| 20:04 |
subscription functionality that we want for our app. |
| 20:12 |
Once you’ve filled in the endpoint and the events, then click add endpoint. And now your webhook will be set up and you can |
| 20:20 |
click here to get your webhook secret key. So now we should have all the keys we need to integrate Stripe with our project. |
| 20:28 |
If you missed one of them, then just rewind this chapter. And again, here’s the Supabase CLI command you need to |
| 20:34 |
run to set up the secrets in the Supabase project. So go ahead and run these for each of the keys. |
| 20:41 |
We’re going to need the Stripe API secret key, the price ID and the webhook secret. |
| 20:47 |
So back in my terminal, I’ve set up all three keys. And to confirm that I can run Supabase secrets list. |
| 20:56 |
And that will show me all the different secrets that I’ve registered with my Supabase project. So at this point, you should see four of them. |
| 21:04 |
Now there’s actually one more place where we need to set up our Stripe secret key. And that’s going to be in our vault table in the database. |
| 21:12 |
And this is an inbuilt Supabase table where we can store secret keys that our database can use as part of automatic triggers. |
| 21:20 |
In this project specifically, I’m using it so that I can make Stripe create a user for |
| 21:26 |
us whenever we create a user in Supabase. Because there are different user systems, but we want them to be associated. |
| 21:33 |
We’re going to implement that using a database trigger. But to do that, it will need to have the stripe secret |
| 21:38 |
key so that it has the authority to create new users. To add this, go back to your Supabase dashboard and then go to SQL editor. |
| 21:46 |
And that in this window, we’re going to run this command. |
| 21:52 |
Just remember to replace this with your actual secret key from Stripe. And then click run and then you should see that it should |
| 22:00 |
create this key for you and return a key ID. And if you’ve accidentally added the wrong |
| 22:06 |
secret or you just want to update it, then you’ll need to use this command instead. So now that we’re done setting up our dependencies, let’s go |
| 22:14 |
back to our Supabase project and set up our database next. Our database is going to be a Postgres SQL database |
| 22:21 |
and we’re going to create three tables. We’ll have a profile table for each user. |
| 22:28 |
There we will store information about their account status. Now this is going to be read only for the user. |
| 22:35 |
It’s also going to be linked to an auth table, which comes out of the box with Supabase. This means that our user ID primary key in |
| 22:43 |
this profile table is going to map directly to a user ID in the auth table as well. |
| 22:50 |
And you’re going to see this pattern where we use a primary key for the user as a foreign key in each of our tables. |
| 22:58 |
Now our most important table is going to be this task table here. We will store each task as a row and it will have a user ID as part of its key. |
| 23:09 |
And finally, we’ll also have a separate table to track the usage of each user per month. |
| 23:15 |
And the reason I decided to use a separate table to track the usage is that I think it will |
| 23:21 |
be easier to scale that way, rather than tracking it in the user profile table directly. |
| 23:27 |
So this is going to be the schema for the database. But on top of this, we will also have security policies and triggers. |
| 23:35 |
We’re going to use something called row level security. That basically means that to be able to read or update a |
| 23:42 |
row of a database, certain conditions have to be met. For example, we can check if the user ID of a request matches |
| 23:50 |
the user ID value of the row that we want to access. And then we use row level security to enforce these roles for our app. |
| 24:00 |
And we’re also going to have something called triggers. Triggers are functions that we can execute when |
| 24:05 |
something happens inside our database. And these functions are run by our dedicated PostgreSQL server. |
| 24:12 |
In this project, we will use them quite a lot. We’ll use triggers to update task limits for each user whenever they create a task. |
| 24:20 |
We can also stop them from creating new tasks once they’ve reached their limit. We’ll also use it to automatically create a Stripe |
| 24:28 |
user whenever a new user is created in our system. That’s because, as I mentioned before, Stripe has its own user system. |
| 24:36 |
So we need some automation to link them together. And finally, we can also use it to automatically clean up our |
| 24:42 |
users and our storage when things are deleted as well. Now, that’s a lot of stuff I just went through. |
| 24:48 |
So how are we going to implement all of that very quickly? Well, with Supabase, we can write instructions |
| 24:54 |
for all of those things using SQL files. And if we go back to our project and then we |
| 24:59 |
go to the Supabase migrations folder, you’ll see that we have a bunch of SQL files for each of these things that we want to add. |
| 25:06 |
And if you click through them, you could see the statements used to create the tables. So here’s the table schema. |
| 25:13 |
And you can also see triggers being created and security policies being created. And the reason I’ve separated each of these statements |
| 25:21 |
into separate files is just to make it easier for you to understand each new thing that we’re setting up. |
| 25:28 |
It’s exactly the same as if I had all of these statements in one giant file, but that’s just going |
| 25:33 |
to be a little bit more difficult to read. To apply these files to a project, you can run this command. |
| 25:40 |
This is called apply a migration. It will execute all of the SQL statements in each file in lexical order. |
| 25:48 |
And so if you go back to our project, you’ll see that each of our SQL files has a number in front of it. And so basically that’s the order that I want to run the files in. |
| 25:56 |
But in a real world situation, I think that people would typically use a timestamp for this number. |
| 26:02 |
So I’m going to go ahead and run this now in my terminal. And once the command is done, Supabase will have |
| 26:08 |
created all the databases, triggers, and security policies that we told it to in those SQL files. |
| 26:16 |
Now notice if I try to run the command again, it doesn’t actually |
| 26:21 |
do anything, even if I change the contents of these files. That’s because these commands, once they apply a migration file, |
| 26:30 |
it kind of remembers that it’s already done that file. So if you want to create new migrations, you actually |
| 26:37 |
have to create a new file and just make that number in front of it keep increasing. |
| 26:43 |
But if the project is still in development like this one here, and you wanted to do a full reset, you can run this command instead. |
| 26:50 |
This will clear your entire database and then run every SQL file from the beginning. And once you finish running your migration, you can |
| 26:56 |
go to your Supabase project to check it out. So go to database and then go to schema visualizer, and you should |
| 27:02 |
see the schema for the database that you just created. And something very cool that I want to mention about Supabase |
| 27:09 |
is that it automatically creates an API for your database. So you can do CRUD operations from your front end really |
| 27:16 |
easily without having to implement the API yourself. You can read more about that feature inside the REST API |
| 27:23 |
or the Data API documentation on the Supabase website. Now back to the app, one of my favorite features here |
| 27:30 |
is that users can upload images to their tasks. To implement this, we’re going to use Supabase’s storage feature. |
| 27:37 |
And I have some good news for you. If you ran the previous command, then you’ve already set this up. |
| 27:43 |
One of our SQL files from the previous step actually creates something called a storage bucket. It did that by creating an entry in this built-in storage buckets table. |
| 27:53 |
And behind the scenes, that actually causes Supabase to set up a storage bucket for us. |
| 27:59 |
So if you go back to your Supabase dashboard and then you go down and click storage, you’ll see that it’s created a bucket for us here. |
| 28:06 |
And the bucket doesn’t have anything in it right now. But if you go here and click edit bucket and click on |
| 28:12 |
additional configuration, you’ll see that we’ve actually configured the bucket already from our SQL schema. |
| 28:18 |
We’ve configured it to restrict the upload size to one megabyte, and we’ve also configured it to only accept images. |
| 28:25 |
Now I do want to mention that I did make this bucket public, which means that if people have the URL to an |
| 28:31 |
image, they can actually just go ahead and see it. And I did that because it’s more simple to set it up with the front end. |
| 28:39 |
But if you were doing this for real, then I probably recommend making this private. It’s just that it’s a little bit more complex to set up. |
| 28:46 |
So it’s a little bit out of scope for this video. So now we’ve set up the database and the storage, |
| 28:51 |
and we’re moving on to the final setup step, which is deploying our edge functions. |
| 28:57 |
Edge functions are custom functions that run on demand in response to HTTP requests. |
| 29:03 |
Think of them as a way to run any code that you’d normally need a server for. In our project, you’ll find them in the Supabase/functions folder. |
| 29:11 |
Each subfolder is an edge function. The code is implemented as a TypeScript function, |
| 29:16 |
and it will be run in a Deno environment. So here, I’m just going to go back to the project to show you where they are. |
| 29:23 |
Go to your Supabase folder, and then go to your functions folder. And then each of the functions is going to be its own separate subfolder. |
| 29:30 |
If you open that up, you’ll see this index.ts file, and that is the code for one of our functions. |
| 29:37 |
Now, we will be able to build and deploy these functions directly from our project using the Supabase CLI. |
| 29:45 |
They also support environment variables, which is where we can go and fetch those secrets that we |
| 29:51 |
stored earlier when we set up our dependencies. Here’s a short snippet from one of our functions, |
| 29:57 |
and it’s the function called createTaskWithAI. This function will create the task and then put it into the table. |
| 30:04 |
And after that, it will use AI to determine automatic tag or a label for the task based on the task title, |
| 30:11 |
and then it will update the task with that tag. The second function is called createStripeSession, |
| 30:18 |
and we’ll be using this in the profile page. So this is here, and when users click this to |
| 30:24 |
manage their subscription, this function will generate a URL for them, and this URL will |
| 30:30 |
either be a checkout session or customer portal depending on the user’s account status. |
| 30:36 |
Finally, the third and the last function is our webhook endpoint for Stripe. So if you recall from the Stripe chapter, this |
| 30:43 |
is an endpoint that Stripe will use to send us event notifications when something happens. |
| 30:49 |
We will use this to detect when the user should be upgraded to premium or when the subscription ends and |
| 30:54 |
they should be downgraded back to the free tier. And as I mentioned before, these functions will all have |
| 31:00 |
access to the Supabase secrets that we stored earlier. So that’s how they can access services like Stripe and OpenAI on our behalf. |
| 31:09 |
From our project root, you can use these commands to deploy each of the functions to our Supabase project. |
| 31:16 |
Once that’s finished, you can go back to your Supabase dashboard |
| 31:23 |
and then check them out by clicking edge functions. |
| 31:29 |
And if everything worked correctly, you should see three separate edge functions being created for us. |
| 31:35 |
If you click on one of them, you’ll also be able to see links to metrics and logs. So this is where you can go to debug them. |
| 31:43 |
Now there’s one more thing we need to do. Click on your Stripe webhook function and then |
| 31:48 |
go to details and then scroll all the way down to function configuration and then click to disable |
| 31:55 |
enforce JWT verification and click save. This verification is there to check that whoever calls |
| 32:01 |
this function is one of our authenticated users. And that’s what we want in most cases. |
| 32:08 |
But in this particular case, we’re expecting Stripe to call this function. And with that, we finally finished all of our setup |
| 32:16 |
process and we’re ready to run the project. Go back to your project terminal and run this command |
| 32:21 |
to start the local development server. Once you’ve run it, you should see this local URL pop |
| 32:29 |
up and you can click that to open your project. And if it doesn’t load right away, you might need |
| 32:35 |
to refresh it, but you can probably now test that each of the features work as intended. |
| 32:41 |
So we can log in with Google. We can create a new task. |
| 32:52 |
And when we create a task, we should see that it automatically assigns a label for us that is appropriate for the task. |
| 32:59 |
We should also be able to edit a task and add images to it. And then if you go to your profile page, you should |
| 33:08 |
see that your task created is tracked properly here and that if you click manage subscription, |
| 33:16 |
you get taken to a Stripe checkout page. And then finally go back to our project and just make sure that you can sign out. |
| 33:24 |
Now if you wanted to deploy something like this, then the easiest way to do this is probably with Vercel, |
| 33:30 |
but this is basically just a static NextJS website. So you can use any other process that works for static websites in general. |
| 33:37 |
If you wanted to add new functionality or extend the project to do something specific, then here’s |
| 33:43 |
a rough overview of the project structure. The UI elements are in the apps and the components folder. |
| 33:49 |
The front-end logic is in the hooks folder, so that’s the client that will connect to Supabase. |
| 33:55 |
And the backend logic is in the Supabase functions folder. And the database and configurations are in the migrations folder. |
| 34:03 |
As I was working on this project, I also actually created an integration test suite so that I can quickly |
| 34:09 |
and more easily test the project’s functionality. You’ll find all the test code in the project under |
| 34:15 |
the test/integration directory, and these tests will actually connect to your real project. |
| 34:21 |
If you want to run them, then create a file like this to store all of your environment variables |
| 34:26 |
that are going to be used in the task, and then update them with your version of these API keys. |
| 34:32 |
Then go to your terminal and run this command in your project root to run the entire test suite. |
| 34:38 |
You can also use this command if you want to run just a specific file. |
| 34:45 |
Now all the tests should pass, but they might fail the first time due to timeouts because I think |
| 34:50 |
that some of these code paths have a cold start. So if you just run them for the first time, they might take a little bit slower than usual. |
| 34:57 |
So if they fail, then I recommend to try running it again and seeing if it works. So we’re now at the end of the video. |
| 35:04 |
That was quite a large project, and I hope you managed to get everything to work. But if you got stuck or if you have any questions, |
| 35:10 |
then feel free to leave a comment either here or on my GitHub page for the project. |
| 35:16 |
Now as I said at the start, this was a very high-level overview of using Supabase. |
| 35:22 |
We went through a lot of stuff very quickly, and there’s a lot of details that I simplified along the way. |
| 35:28 |
Now if you are interested in diving a little bit deeper, then go to the project repository and check |
| 35:34 |
out this tutorials folder where I’ve actually created a bunch of different documents for each major |
| 35:40 |
functionality that we introduced to the project. If you did enjoy this and would like to see a tutorial |
| 35:45 |
series covering each of these features in more detail, or you want to see an end-to-end tutorial for a different type of project entirely, |
| 35:52 |
then please let me know in the comments. Otherwise, I hope this was useful, and I’ll see you in the next one. |