📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Windsurf Masterclass: How to Build & Deploy AI Apps | STEP-BY-STEP

Ahmed Mukhtar | AI Automations1:00:03

Transcription

I have spent over 60 hours building AI applications using Wind Surf, and I can tell you now it is the best AI coder available. In this video, I'll explain exactly why that is and show you different examples of applications that I have built, going through step by step how I built them and how to deploy them.

First, we'll start with a very simple invoice analyzer. This allows users to upload documents and select all the different elements they want to extract from the invoice. They then have the option to download the extracted information as JSON or CSV files.

Next, we'll take it up a notch by building a content repurposing application, fully complete with user authentication, Supabase integration, token usage and tracking, and Stripe integrations for payments. Not only that, but we'll also look at how we can deploy these applications so that they're live for users to interact with.

Finally, I'll showcase an MVP application that I built for a client, which is a real-time translation messenger. This application is also fully complete with user authentication, searching and adding contacts, and real-time messaging and translations of every message.

I'll also cover ten of the best practices and tips that I've learned along the way from working with Wind Surf over the past few weeks.

If you're new to the channel, hi! My name is Ahmed. I was a machine learning engineer, and now I'm a generative AI engineer and founder of Agenic AI, where we help businesses implement these generative AI solutions and automations. I also have a school community where I share various resources, templates, and code for every solution that I share with you. We also have weekly Q&A sessions where people hop on, ask questions, and share insights. If that sounds like something you might be interested in, it will be the first link in the description below.

With that being said, let's get started with the masterclass. I've created a document with over 50 pages of step-by-step instructions, including all the different codes and prompts that I've used to build these applications. It covers everything, not just how to use Wind Surf, but also setting up Supabase, setting up Stripe, and for the first application, how we can set up Azure Document Intelligence for extracting different fields from the invoice. If you want access to this, it will also be in the school community, and I'll leave a link to that down below.

As mentioned before, these are the things I'll be covering in this video. We'll start by looking at Wind Surf, how it works, why we should use it, and why it is the best, especially if you're an agency owner building different generative solutions for customers. We'll explore all the different features of Wind Surf, the concepts and capabilities, and what differentiates it from other AI coders out there.

Then, we'll cover the step-by-step instructions for building applications: the invoice analyzer, the content repurposing application, and then we'll be deploying and hosting one of these applications. I'll also give an overview of the client application that I built, the real-time translation messenger, and finally, I'll cover the best practices and different tips and unique insights that I've learned from using Wind Surf in the past few weeks.

So, what is this new IDE that's revolutionizing how we work with AI and build full-stack applications? The company behind it is called Codium, and they've been around for a while now. They started off as a simple code completion extension that you could add to your VS Code, helping developers code faster. However, now they've released Wind Surf, which is essentially the first AI generative IDE. They've built this on top of VS Code because it is open source, so it looks very similar to VS Code, but the backend is powered by agents and co-pilots that work and collaborate with each other. This is why Wind Surf is unique.

They've released Cascade, which combines a deep understanding of the codebase from their original context awareness engine and provides advanced tools and real-time awareness of different actions, allowing for a seamless, powerful collaborative flow.

Some of the features that make it unique include maintaining continuous understanding of your actions. Every time you make an update, it gets updated, keeping track of everything you do. It has a deep understanding of the entire codebase using the contextual awareness engine they had before. They also have an LLM-based code search that is three times more accurate.

Recently, Wind Surf added the ability to upload images, similar to what Cursor does. Now, we can add images and ask it to tweak the UI or build whole new applications based on images of different UIs that we like. Another cool update is from Anthropic, where they introduced a model context protocol, essentially a new standard for connecting AI systems to different content repositories, business tools, and development environments. This should improve the output of the models, especially for code generation. I've partnered with Wind Surf, so we should start seeing improvements soon.

First up, we have the document analyzer, the invoice analyzer. Let's see it in action with a demo before we jump in and understand how to build it step by step.

Starting off, we have a very simple application where we can upload PDF files of an invoice. Here, I've got a sample invoice. We upload this, and we have a PDF viewer where we can scroll and look at the invoice we've uploaded. On the right-hand side, we define the different fields we want to extract. For this demo, I'll extract three variables: the customer name, the vendor's name, and the subtotal.

In the backend, it's using Azure's Document Intelligence, which analyzes the PDF file and extracts all the entities. We can see the customer name is "Test Business," which is correct; the vendor's name is "Slic Invoices," which is also correct; and the subtotal is $85, which is accurate. We can then download the data as a JSON file or a CSV file.

As you can see, it's very simple. However, something like this would take weeks to build from scratch, whereas using Wind Surf, we can create something like this within hours.

Now, let's see how we got to this stage and look through all the different steps we took to build the application.

I want to start with the steps to create the Azure account, which we'll use to extract data from our PDF files. It's quite simple and doesn't require too much work. We start by creating an account at portal.azure.com. New users signing up get a $200 credit to use for the different services they offer.

Once you have that completed, you'll see a page like this, which is the dashboard of Microsoft Azure. You have all the different services they offer. The only one we're concerned about is the Document Intelligence service. To create this, you might not see it at the top, so you just have to click on "Create New Resource" and search for Document Intelligence. The one we want is the Form Recognizer.

Click on it, and you'll be directed to a page where you can create a new service. Select the default subscription, and for the resource group, which is essentially just a group of different services you want to keep together for one organization, you have to create a new one. I have one set up for my agency.

For the region, you have all the different areas where the service could be hosted from, and it's good to pick one that's closer to you. I'm going to choose UK South. Then, we have to give it a name. I'll call it "DOC Analyzer Demo."

For the pricing tier, you should see an option for a free tier if you created a new account. However, I have to select the standard pricing tier. The free tier allows you to do up to 500 pages free per month, while the cheapest paid tier is $150 for 1,000 pages. If you go above that, it drops down to 60 cents per thousand pages, which is not too bad.

Next, we don't have to worry about all the different settings here; we can just jump straight to "Review and Create." Finally, click on "Create," and it will deploy the service. I'm not going to do that because I have a demo set up already.

Once that finishes deployment, you'll see a page like this. If you don't, you can go down to "Resource Management," "Keys and Endpoint," and this is where we'll get the API key. We can copy the first key here, and we also need the endpoint URL. These are the two variables we need later on to connect our application with the Azure service.

Once we have that set up, we're now basically at the stage of creating the application. First, we have to create the Next.js application, which you can do with a simple command in your terminal. Just copy and paste this command, and it creates all the folders and files we need as a starting point for building these applications.

We also have to install the library for Azure using this command. Copy and paste both of these into your terminal, and that should set up the basic structure and folders that we can then open up using Wind Surf and start building our application.

To speed things up, I've created a Wind Surf prompt writer, which is a custom GPT within OpenAI's custom GPTs. All we have to do is paste in the overview of the application we're trying to build.

Let me copy that and paste it here. Essentially, we're giving a high-level overview of what the application does and how users interact with it. They can upload their PDFs, specify the fields they wish to extract from the invoice, and run the execution.

We then specify that it should also use Azure Document Intelligence service to analyze the PDF and extract the data, which will be shown to the user on the right-hand sidebar. We also mention the tech stack we want to use: Next.js, Tailwind, and Lucid icons.

After sending that through, it creates an instructions file. This file is key, and we'll always refer back to it when building the application. It creates a markdown file of the project overview, all the core functionalities and features we want, and it builds up on each other, helping us break up the application so we can build one feature at a time, test it, and ensure it works before moving on.

For every feature, it has a description and detailed steps of what it needs to do, how the layout looks, what actions users can take, and the tech stack needed for that specific feature. At the bottom, we also have the documents section.

This custom GPT doesn't include the different snippets, so I like to paste in the snippets of the documentation inside the instructions file. This will really improve the output from Wind Surf.

At the end, we also have some important implementation notes that it needs to follow. We copy this markdown file and open up Wind Surf. Go to "File," "Open Folder," and select the folder we just created using the terminal.

You should see a basic folder structure similar to this with a basic Next.js application. The first step is to create a new file in the root directory called "instructions.md" and paste in the file we copied.

Here, I've pasted in the final one because the output from the custom GPT won't be perfect. I'd highly advise you to spend as much time as you can on this document because this is what the model will essentially use. We'll refer back to this document when building out the application, so you want to ensure all the features are correct and all the different steps are laid out the way you want.

You might want to take out or add new things and elements. It's very important to get this absolutely perfect before we even start building out the application.

Once you do that, make sure to add snippets of the documentation from the different services we're using. The first one is for Azure Document Intelligence, where I pasted in a bit of information about what it is, what it does, and the exact code from their documentation page. This will really improve the output from the model and minimize errors, increasing our chances of success without having to go back and forth for error handling and troubleshooting.

I've also included a schema for the pre-built invoice, which is the model we use with Azure Document Intelligence. The model has a predefined list of fields it can accept, and we want to ensure the names and data types are correct. The best way is to paste in the exact schema from the documentation to avoid errors when building this out.

We specify all the different fields and paste that in. This is what we use for the dropdown menu to allow the user to select the different fields they want to extract from the documents.

You might think this document is huge with over 450 lines, but we want to keep everything in one place. We'll only implement specific sections at a time when building out the applications.

Once we have that all done and ready to go, we can finally start building out the application. The first thing we want to do is copy the first prompt here. We've done everything, and we want to start by chatting with Cascade using the right-hand sidebar. If you can't see this, just press Command + L or Control + L to bring it up.

What I'm doing here is saying I want to build a Next.js application for analyzing PDF invoices to extract data. Users can upload invoice files, specify different fields for extraction, view the extracted data, and the app also leverages Azure Document Intelligence.

I'm copying parts of the overview to really hone in on what we're trying to do. Then, I tell it to read and strictly follow the instructions based on the instructions.md file. We can link that and ensure it fetches the document.

Finally, I mention that I've set up the Next.js project already, and for this one, it will be the "DOC Analyzer Demo" folder. Now, let's build the first feature and specify the exact name of the first core feature we want to build out.

After entering that, it goes off and does its magic. As you can see, it first analyzes the instructions file. Let's let this run for a little bit, and then I'll come back.

One of the cool parts is that it has a tool that runs terminal commands, so we don't have to copy and paste them into our terminal. We can do everything from inside the Cascade chat. Even if it encounters errors, it can read the errors automatically, go back and forth within itself without me having to do anything, and it suggests that we need to use legacy peer dependencies.

We just have to click accept, and it feels like collaborating with a developer, going back and forth, telling a developer to do this task, and it comes back with the errors. Sometimes it figures out errors and solves the problem by itself, showing everything it's doing and the different steps it's taking. It's very intuitive.

What I like to do is open up the application and test it to ensure all the newly generated content is accurate and running correctly before coming back and accepting or rejecting the code that Cascade generated.

To do this, we run the command in our terminal: npm run dev. This runs our application locally, and we just have to go to localhost:3000 for this one, which I've got opened up here.

Amazing! The first core feature of the application is just a simple drag-and-drop of PDF files to upload them onto our app and view them. Let's open up the sample invoice, and we have our first error, which is good. Let's do some error handling.

We copy the error and come back into Cascade to paste it in. I've still not accepted the changes; I'm just letting it know there was an error. Let's see what it comes back with.

It seems to be an issue with the PDF worker. So, we go back and forth, copying and pasting the errors exactly as shown on the screen, asking it to fix this. The error was with the PDF worker; it wasn't set up correctly.

It also changed the look of the application, which is fine for now because we're not worried about the UI at this stage. Finally, we have it working, so we can upload a PDF and view it.

This is very basic; if it had multiple pages, we could go next or previous. We have the basic functionality for the first core feature. Honestly, there wasn't much I was doing; it was just a bunch of copying and pasting of the errors exactly as shown on the screen, and then it fixes the issues.

Once I was happy, I accepted the changes, and now we can see we have a bunch of new files and configurations set up. At this stage, we're ready to start the next feature.

Before doing so, I like to commit the changes once everything's tested and saved, ensuring the first feature is good to go. It's always good practice to commit changes.

On this tab, we have the source control, where we can connect with GitHub and commit the changes. We upload all our code onto GitHub, thinking of it as a checkpoint. This way, if we mess up the code, we have a save point to refer back to and try again.

We just give it a message and hit commit. The first time you do this, you'll have to publish the branch. Essentially, the first time you upload a new project, you have to connect it with GitHub. A popup will appear where you log into GitHub, and then you can publish the repository as public or private.

You just give it a name and hit publish. This will upload all our files into the repository. You can see here we have the first commit, and we're at a good point now. Everything's safe, and there are no more changes shown on the folders and files.

Now we can copy the second prompt for our second feature. Another tip is to always make sure we start a new chat whenever the chat window gets too long. This is because the context window gets filled up with all this information, which we don't want, and it can start to affect the model's performance.

You probably noticed that at the start, it generates code really well, but as the context window gets bigger, the performance worsens. So, at every step, we want to create a new chat, paste in the second part of the prompt, and say, "Continue building my Next.js application."

I give a brief description and always refer back to the instruction file, saying this is the instruction file, make sure it's connected, and we implemented the first feature. Now, continue and implement the second feature, giving it the name.

This is a key point: please don't mess up the existing functionality because it sometimes likes to regenerate the whole code. We want to ensure it doesn't do that every time we start a new feature.

We hit send and wait for it to do its magic. The second feature was the field definition interface, and it just finished creating the field definitions file, which has all the predefined fields we want.

We can see here that it's not actually correct, so it needs a bit more prompting. I'm going to paste in this command: "Could you add all the predefined acceptable fields that the model allows? You can find a complete list in the instructions file."

This makes it clear that it needs to use the instruction file specifically for this section and include all the fields exactly as they're written with their correct field types.

This should hopefully prompt it to check the documentation section at the bottom where the schema for the predefined fields is located. Amazing! It did a good job of taking all the different fields with their right types and descriptions.

I think that was the only thing we wanted for the second feature. It looks like we also wanted to implement the dropdown menu, so let's see if it did that.

Let me refresh. As you can see, it works! It did the job; we have all the different fields, and we can add them. It shows it down below.

The UI is not great, and usually, I wouldn't worry about this too much, but because it's so bad, we want to improve it before moving forward. Once we start adding multiple features, it might get a little too messy.

I'll improve the UI before we move forward. First, I want to ensure that the upload feature still works. We always want to test everything at every step to ensure we haven't introduced any new errors and that everything we previously did still works.

Yep, that's all good. It's just about the UI at the moment. Now that we have the image upload feature, we can upload this screenshot.

I'm just going to say that the UI is terrible and to fix it while ensuring not to touch any of the functionality. Let's see what that does.

While it's doing that, we can check the completed parts to ensure it's only modifying the UI part of the code. Everything above is the functionality, and we want to ensure it only modifies the UI.

It looks like it finished. Wow, yes, much better! We can see we have the upload here, the viewer at the bottom, and we can add things here.

Cool! Nice touch. We can now move on and accept all the changes. We can start on the third feature: data extraction with Azure Document Intelligence.

Let's copy the prompt for a new chat. I've already committed before updating the UI, so I'm not going to bother doing that again.

This part is good to go. It's the same prompt again, where this time we're just saying we've done the first two features. Now, continue and do the third feature.

It goes ahead and analyzes the instructions, analyzes the page, and for this one, we want to set up the API to talk with Azure. We want to see the extraction results, include a button to run the execution, and a loading spinner for the progress.

Here are all the steps it needs to take: set up Azure, make an API route, use the environment variables, map the user-defined fields to the schema, and implement error handling.

Nice! We created all the different files we need for this feature. It asks us to create the env file, where we store all our environment keys and secrets.

We copy this and insert it. This is what we'll use to connect our application with the Document Intelligence service. We just need the endpoint and our key, which I showed you where to get.

Let me go ahead and do that real quick. Cool, that's in there now. It also asks us to install some new libraries, so let's let it do that.

In this section, the only UI component is the "Run Extraction" button, so let's check. Yes, we have that! The "Extract Data" button is here, but it's disabled because we don't have data.

Let's add some data and then hit "Extract Data." Amazing! It looks like we're also showing the data extraction, so it seems we've implemented the fourth feature as well into the third feature, which is fine.

What I like to do is ensure that it has done this correctly. I've got this prompt here, and essentially it's the same thing again: continue with our application.

I've already implemented the first three features, so continue with the fourth one. At the end, I mention that most of this has already been implemented; just make sure there's nothing missing.

I won't bother starting a new chat or committing changes because this is essentially the same feature. We just want to ensure we've implemented everything, test it, and then commit to GitHub.

It looks like a couple of features want to be added. Let's see what it looks like. Let's add a file and ensure this all works before moving on.

Oh, nice! We can collapse the data as well. Perfect! Accept all changes. Now, let's check this error we have here.

What I like to do is copy this whole section into the chat, then hover over where the error is, copy everything, and paste that as well. I don't even need to say anything; it already knows where the error is.

This is the error, and it knows we're looking at the route.ts because this is what's highlighted at the moment. It can fix that automatically.

Sometimes, if you make changes to a file and haven't saved it, you wouldn't be able to implement the changes. So, I just saved the file and came off it, then asked it to continue because it can't edit a file that hasn't been saved yet.

Make sure it's always saved. Right, so it made a bunch of different changes. Let's test it to ensure we haven't messed up anything.

Oh, that's nice! It even has a little information icon for the invoice ID. That's working amazing!

We fixed all the errors, so we can go ahead and accept all the changes it made. Just make sure we've implemented everything for this stage.

Yep, we have everything here; it's all working. We can finally commit the changes. This is the third feature, which was the display of extracted data.

Now we can go on to the final instructions.md. Because this was in a really long chat window, we can add this very small feature at the bottom here.

The final feature is the ability to download the data in both CSV and JSON formats. We can have the download button convert the data into the chosen format, using Blob and URL.createObjectURL for the download functionality.

That will essentially be the final feature we have to build, and then it's just about customizing the UI, making sure it looks how we want it, maybe adding a logo and style that we like.

It seems like it's completed everything. Let's run our application, upload a file, and add a couple of fields: customer name, invoice date, vendor name.

I really like this; it's even better than the one I created initially. Extract the data, and I like how you can hover over the information icon, and it gives you a bit of information about the data.

Extract data: invoice details, invoice date, customer name. It even splits into different groups of data, which is really cool.

Let's download the JSON file, save that, and then download the CSV file as well just to quickly see what that looks like.

I'm going to open them up inside here. Customer name, test, invoice date, and then the vendor name. For the JSON, we can drag this onto here as well.

Very nicely put: customer name, invoice date, and vendor name. So that's basically the whole application. You can see how quickly we've spun this up.

Of course, now we just have to worry about the UI. What I want to do is try this. Let's see if this works. I'm just going to paste in the UI that I created.

I'll take a screenshot of this and add it here. Let's press accept all the changes, and there are no errors.

Please update the UI to look like the reference image and ensure not to touch any of the existing functionality; only update the UI. Let's see if we can get it to look like the one I created.

Right, so I finished updating all the pages, pretty much every single component here, and it told us exactly what it did and the colors it used.

Let's see the moment of truth. Oh wow, that's very close! Super close to what I had. Let's just make sure it all works.

I'm going to extract the customer name and see what it comes back with. It really does look very similar to what I had before.

Oh, there we go! Amazing!

When it comes to deployment, we essentially have to do npm run build and ensure the app compiles and builds with no errors before we can save and commit to the repo.

I'm not going to go through this for this application; I probably will do that for the second one, which I'll go over in just a second.

I've also included the final instructions prompt, which you can just copy and paste. This is the instructions.md file we created earlier, and this is in the document.

Next up, we have the Social Scribe, which is a content repurposing application I made to generate articles and social media posts for LinkedIn and X.

This one is a step up from the previous application because it has a lot more complexity, and the features are a bit more involved, especially when it comes to integrating with Supabase, the Stripe integration, and ensuring we're tracking all the tokens.

We need to make sure we're limiting users so that if they don't have enough tokens, we don't allow them to generate anything until they top up.

Let's first start by showing you a demo, and then I'll explain how I built this application.

Here, we've got the sign-in page, and we can either log in or create an account if we're a new user. Let's create an account and hit "Create an Account."

As soon as we create a new account, we have to go through an onboarding process. This is where we capture all the details about the person's company, their brand voice, their target audience, and content preferences.

I'm going to quickly fill out all the different fields with Airbnb's company in mind for the sake of the demo.

I just finished completing the form with all the different information about Airbnb. Next, we have the brand voice, which sets the primary tone, secondary tone, and some voice characteristics.

We also have the target audience, where we set the primary audience, demographics, psychographics, and we can add a secondary audience, but we don't need to at the moment.

Finally, we have the content preferences, which is how we want the content to sound. This includes the post type, post style, writing style, key topics, content pillars, unique value proposition, and key differentiators.

Once we complete everything, we can click "Create Profile," and that should save our persona. You can see the alert messages as well, and it takes us inside the application.

We have a few tabs here. The first one is the Persona tab, where we can modify everything we've just entered and make changes.

Next, we have the article page, where we input the content we want to repurpose into our own. We can have a topic name and then put an article link, a YouTube link, or just paste in plain text if we just have an idea.

Let's try an example here. I have this random video about how to make money on Airbnb, so I'm going to copy this for the title and then copy the link.

We have to set this to YouTube link and click "Generate Article." We have the loading screen, which lets users know something is happening while we're generating an article.

This is just good practice for any UI design, so let's give it a second.

I want you to pay attention to the success message here, which shows us how many tokens we've actually used to generate this article.

We can get rid of that. We have the article here; you can see it's really good and huge. I'm not going to read it, but it has everything we want.

The idea here is that we don't actually care about the article. I mean, we can if we want to put the article in a blog, for example, if we want to create a blog for the website, we can use this article.

But essentially, we want to use the articles for social media posts. Here, we have a dropdown menu with all the different articles we've generated, and this gets pulled in from Supabase.

As soon as we generate an article, it gets saved into our Supabase database, and this dropdown menu pulls in all the different articles we've generated.

We select an article, and here we define the type of post we want to create. For this one, we can do tips and tricks. The style of the post could be problem-solving, and the writing style could be educational.

Let's first see Twitter. It's generating. Cool! We have content here that we can just copy.

Let's try a LinkedIn post. At the bottom, again, you can see the tokens we've used to generate it. Here we have the LinkedIn post.

These are just for the sake of the demo and the project, and this can be improved a lot. I just didn't have the time to do so.

Finally, we have the settings page, and this is where the magic really happens. Here, we can see all the different tokens, the available tokens we have left.

When a new user joins, they get 10,000 free tokens, and we've used up 5,000. We can see how many we've purchased, and once we purchase tokens, we can see the bar showing us how much we've used in comparison to the amount of tokens we've purchased.

At the bottom, we have the different packages. It starts off at $5 for 50,000 tokens, $15 for 250,000, and $40 for 2 million tokens. We can click on "Purchase," and this should take us to the Stripe page.

Cool! We're in the Stripe page now, and here we have the test mode for obvious reasons. We've entered our information, and we can just click "Pay" and let it process.

Amazing! Now we should redirect back to our settings page. We can see here, "Payment successful! Your tokens have been added to your account," and we have a total of 54,000 tokens now.

We can also try the ultra package just for the sake of the demo. There we have it; now we've got 2 million tokens.

We also have a logout button. You guys can't see that, but on the left-hand side, we have the logout button, which takes us back to the sign-in page.

Now you have an idea of what the app does and its capabilities. Let's dive into how we got to this stage and go through the different steps.

For this one, because it's a bit more complex, I won't actually be building it from scratch, but I'll take you through all the different steps I had to do to build it out.

We started off with the Wind Surf prompt writer, as usual. I gave it a more fleshed-out prompt because I wanted to ensure we captured all the different details, especially for the onboarding form.

I told it about the different tabs we have: the persona page, article page, social media page, and settings page. At the end, I said to use this tech stack and ensure it's a modern, responsive UI.

This was the prompt I entered into Wind Surf, and it came back with the instructions prompt, which I can show you.

Here we have the final instructions file, and you can see how I've split this up into all the different features. I'll go through that in just a second.

Similar to the other application, we start with the overview. This is the overview of the app and what we're trying to do. We want to ensure to use Anthropic's model for the LLM, Supabase integration, onboarding form for the company, setting up the company persona, generating articles, social media posts, and managing and tracking token-based generations with Stripe payment integration.

This is the tech stack we wanted to use. Let's go through and explain all the different features and how I've broken it down.

Because we're using Supabase for not just authentication but also storage of the data, personas, and the different content we generate, we need to ensure this is all fleshed out from the start.

When it comes to building the rest of the features, everything is set in place, and all the tables are there and set out correctly.

As you can see, we have four tables: the profiles table, which has the user's details; the personas table, where we keep the company persona and content style; the content table, where we store all the content we generate; and finally, the tokens table to track usage for each user.

I can show you what this looks like inside Supabase. Here, I've got my Supabase set up. Inside the table editor, we have the four different tables.

Let's start with the personas table, where we keep all the information about our persona. The first one was just a test for my agency, and the second one is the one we just did for Airbnb.

Then we have the profiles table, where I have my test email and John Doe. We have the created and updated columns.

Next, we have the content table, where we store all the content we generate. You can see a bunch of data here, and the content type is either LinkedIn or Twitter.

Finally, we have the tokens table, where each user has their available tokens, total tokens purchased, usage, and last purchase date.

To get started and set up Supabase, we have to create a project at supabase.com. We create a new project, give it a name, password, and region. You'll be given the project URL and the anonymous key from the Supabase dashboard.

Just copy that into your .env.local file, and that's how we connect our application with Supabase.

Once we tell Wind Surf to start with the first feature and implement it, after it builds all the different files, we generate this schema file for our database.

This will be located under Supabase migrations, and it will be called initial schema. It looks something like this, and this is basically SQL code to create all the different tables, fields, columns, and some policies and functions.

We have to copy this whole code and go into the SQL dashboard. You can either do it through the CLI command line interface or through the dashboard.

In Supabase, under the SQL editor, create a new snippet, paste in your SQL code, and click "Run" at the bottom right. Once you click "Run," this script will build out the whole Supabase database, and we don't have to worry about it.

The second feature is a simple sidebar navigation with all the different tabs we want: the persona, article, social media post, and settings tab. This was a very simple feature that we just added.

The third feature is where we implement the persona tab. This showcases the persona that the user entered from the onboarding process, allowing them to modify their pre-filled data.

It's connected with Supabase, so it pulls in everything they've entered and gives them the option to modify different parts and save it back to the database.

Again, this wasn't a hassle to create; it was quite simple. Just tell it to build out this feature, and if there are any errors, copy and paste them, and you'll finish this part.

The fourth feature is where it gets more interesting. This is where we create the article tab for generating articles.

We're telling it to create a new article page with all the different inputs and dropdown menus, ensuring we use Anthropic's API to generate the inputs.

Here, you can see how I've referenced the documentation section, so it knows to check the documentation for Anthropic's API data.

I've pasted in an example of an article generation prompt, giving it the prompt and passing it all the different variables we want to use to generate the article.

Once it created that, it still wasn't capturing the tokens, so I added this prompt, asking it to handle the response correctly and ensure we capture the token usage.

I also gave it another example inside the prompt itself, taken from the documentation of Anthropic's API website, and this fixed the issue.

Now we're able to see the response with the tokens we used for the generation, and we capture everything to pass it back to the database.

Then we moved on to the fifth feature, where we do the social media post generation. This is very similar to the article one. It creates a social media page, fetches the previously generated articles from a dropdown menu, and allows users to select an article, define the post preferences, and click "Generate" to generate the post.

This one was also quite simple and straightforward; it didn't cause too many errors.

Next, we built out the tokens management feature to track token usage and show the user's balance inside the settings page.

For this one, I just asked it to create the feature and add the settings page to view the token balance. I also told it to only allow users to generate articles or posts if they have enough balance.

This was a modification because initially, it set the default token to be 100,000, but I dropped that down to 10,000. I told it to keep in mind that users purchase more tokens, so the limit may change.

For the final feature, we implemented the Stripe integration. This allows users to purchase additional tokens via Stripe.

The key here is that I pasted a bunch of snippets from the documentation for using Stripe, which helped a lot and made the whole process smoother when generating the code.

When it comes to the Stripe side of things, we need to have an account. We create a new product, give it a name and description, and for that same product, we can have three different prices.

Make sure they're all one-off, not recurring prices. For every price, you can click on that price and copy the ID, which we'll use to connect with the application.

I'll show you how that looks in just a second. Essentially, I told Cascade these are the different packages I have, so make sure to update all the areas where the packages are displayed.

It made some default values that I didn't want to use, so I wanted to ensure it uses the ones I've created inside Stripe.

In our .env file, we have the example file here. First, we have Supabase, which includes the URL, anonymous key, and service role key.

For Anthropic, we have our API key, and for Stripe, we have a few different keys: the secret key, the webhook key, and this is the webhook we set up to redirect back to our application.

This is usually a public URL, but I'll show you how to set this up for local host testing. This refers to all the different packages and price IDs for each package.

To set up our webhook endpoint inside Stripe, go to the Stripe dashboard. Make sure you're in test mode because you want to ensure it all works first before copying it over to the live version.

Once inside test mode, go to Developers > Webhooks, and this is where we add an endpoint. Click on "Add Endpoint," give it a name, and this has to be a public URL for it to work.

This is basically your application's URL once you deploy it. We can just say "Social Scribe" and don't need to give an example.

Select the event you want to listen to: "checkout.session.completed." Make sure you check this one, and it listens for when the checkout has been completed.

Ensure the version matches the one you're using; I'm using the latest one, so I'll pick that one and click "Add Endpoint."

I'm not going to do that because I already have it set up, and that will give you the webhook secret key, which we paste into our .env file.

When it comes to local development, we have to install the Stripe CLI (command line interface). If you're on Mac, just use Brew install Stripe, and then authenticate by using this command in your command line.

This will take you to Stripe's webpage to log in, and that's how we authenticate.

We have to forward the webhook because it's not live yet, so we forward the webhook we created onto our local host URL using this command.

We have to keep this running every time we're running the application. In my terminal, I have two different terminals: one for running the application (the node) and the second one for Stripe, which is running the Stripe webhook URL forwarding.

Make sure you stick it in because I'll also show you how we can minimize the different errors we get and ensure Wind Surf listens to the instructions, speeding up the development process.

The final thing I did was just final UI improvements. I used this prompt to make it look a bit nicer and added a loading UI animation for when articles were being generated.

As always, we have to test it, save it, and commit to the repo. To prepare for deployment, we have to run this command.

Let's close off the server and start it by running this command. This goes through and builds the whole application, ensuring there are no errors when building it for the production environment.

The first time you do this, you're bound to get a bunch of different errors, and most of the time, they're very simple TypeScript errors.

All you have to do is copy it, paste it onto Cascade, and say, "Please fix this." You can actually test this by pasting three or four different errors because you're going to get a bunch of different errors.

You can copy a bunch, about three or four max, and then ask it to fix it. Here, I've only got one because I've gone through this process a few times, but you're most likely going to find a bunch of different errors.

Cool! All it did was modify one little line. Let's check it out; it was just an apostrophe we had to escape.

Accept all changes, and let's run that command again: npm run build. Just make sure there are no errors at all.

This time, we finished with no errors. You can see everything is good; it built out all the different pages.

At this stage, we want to save this checkpoint and commit all the different changes. I'm just going to say "Ready to deploy."

This is the second time I'm doing this, and you can see it down here as well. There are a bunch of fixing errors, but it's always good practice to commit as often as possible whenever the application is in a good state where everything's been tested and is working.

Sync changes, and we're basically ready to deploy.

Just quickly, we have the complete prompt here, which will also be added to the masterclass file. Now we're ready to deploy our application.

You have a few different options to choose from. I like Railway; it's very simple and cheap. You can also use services like Vercel or Render. Railway is really good for me, and they have a cheap hobby plan of just $5 a month for small, simple projects.

This is the one we're going to use today. We start off by going to railway.app, click on "Deploy a New Project," and log in with your GitHub account so that it's all synced in.

We want to deploy from a GitHub repo, so select this and choose the repository of our application. Mine is called "Social Scribe."

Click that, and we want to add the variables because this is important. All the environment variables we had in our local file need to be copied and pasted onto here.

A simple way to do this is by using the raw editor. Click on "Raw Editor," and copy and paste everything from your local .env file into the raw editor.

Once you've done that correctly, you should see something like this, with all the different variables and API keys hidden.

Go back to deployment, and we can see that deployment is in progress. At the moment, it's doing the build we did locally when we ran npm run build.

It's ensuring it compiles the whole application and then deploys it. We can see that there was actually an error, which is good because we can troubleshoot together and see what the problem was.

I'm going to copy everything up until where it was working because the error is somewhere here. Then, go back to Wind Surf, start a new chat, and say, "I got this error when building the application in production. Please analyze the code base and find the root cause."

I'll reference the whole source code and see what it comes up with.

It's saying the Stripe secret key is not set in the environment variables. Let me quickly check.

It might be because we took a little longer to put all the variables before it managed to build the application. I'm just going to retry without changing anything.

I'm pretty sure it should be okay. It's looking good; it built successfully!

Let's close this. It's just deploying. Give it a second. Deployment successful!

If we go to settings, this is where we can connect our custom domain or generate a domain. Now we have a public domain.

If we click this, we can see the application is now public. If we scroll to the bottom, you also have some variables that you can change, like the region where you want the service to be hosted.

You can limit the amount of CPU and memory the application uses, and there's a bunch of stuff here that you can mess around with, but we don't need to worry about any of that.

The application is running, it's live, and everything's good to go. You also have the metrics tab, which keeps track of the CPU and memory of your application.

If we go to the one-hour view, this is just recently deployed, so we're not going to see much going on here.

It's a very simple and easy way to deploy our application, and that's all we have to do.

Finally, we have the Lang Link application, which was a real-time translation messenger. This was a project for a client who wanted to build out a quick MVP to test the idea.

Let's show you a quick demo. I've got my test account here. You have a profile page where you have your name, email, and preferred language.

I want to talk in English and receive translations in English. We can also toggle the theme between light and dark. I quite like the dark theme.

Next, we have the contacts, where we can search users by name or email. For example, we can search for Jack and see him here.

We can add him as a friend and see the pending invites. We have a list of our contacts, and we can start chats with them.

Finally, we have the messaging tab, which is very dynamic and mobile-friendly. The idea here is that it needs to be used for mobile as well, so it's very mobile-friendly.

Basically, we can chat with different contacts. We send a message, and our message is sent in both the language we set and the translation.

Jack previously had his language set to English, and then I changed it to Spanish. He sends this message, and this is what I receive in English.

It's able to send out the messages in both my language and the other user's language. We can quickly type in a message.

This video is very long, and you see how fast that was. It sends the message and translates it.

Yeah, it's a really nice app, and the client loved it. Now, let's show you how I built this using Wind Surf and go through the instructions file.

We have the instructions file here for the Lang Link application, and as you can see, it always follows the same format.

We start with the project overview. We want to build out a web application to facilitate real-time translation messages between users, with user authentication, responsive design, and a contacts list for real-time communication updates.

The technologies used include Next.js for development, Supabase for the backend, and OpenAI's chat model for translation functionality.

I could have used Google API for translation, but I wanted to keep it simple for this MVP, and it worked really well. It even handles emojis, which is great.

For example, if you send an emoji, it's able to pass that on after the translation, so it actually worked in our favor.

For the functionalities, I split up all the different features. I started with user authentication, telling it what users can do: sign up, log in, and manage their profile settings.

Next, we had the message interface, which was the chunk of the application. We wanted to ensure it looks nice and presentable, and the functionality needs to work well.

The main idea here is to use Supabase's real-time messaging capabilities, which is why you see it was really fast when sending messages.

The user will also receive messages instantly, which is key because it's a messaging platform. For the UI, we needed to ensure it's mobile-friendly, with a clear separation between sent and received messages.

It needs to be very clean, so I spent a lot of time ensuring the UI is consistent across the platform.

At the bottom, I've referenced the documentation section, so it goes and checks the documentation where I pasted in a snippet just to show an example of how this can look.

This is the system prompt I used: "You're a translator specializing in translating from the user's language to the other user's language. Translate the following text; only return the translation and nothing else."

This worked really well. Then came the contact list, where users can search for users, add them, send requests, accept requests, and initiate chats.

Again, this was very simple and straightforward, using Tailwind for the UI to fetch and display registered users from Supabase and implement search functionality and chat initiation.

This was also a straightforward feature. Then came the translation service, which is sending messages to the OpenAI model and returning the response.

At the bottom, I've referenced the chat model documentation. Most of these were created in a previous feature, but we always want to build upon it and ensure it's done correctly.

By asking it to refer back to the instructions file and double-checking, we ensure everything is done right.

Here's a good example: the real-time communication. I'm pretty sure it was done the first time around, but we want to check again to ensure it's using real-time messaging and updates with Supabase.

Finally, we optimized for mobile, ensuring the UI adjusts seamlessly between different screens and is consistent throughout the application.

That was pretty much it for this application. You can see it really doesn't take that much, and this was a fun project to do.

Now, let's look at the best practices and tips. If you spend any time building applications in Wind Surf, Cursor, or Bolt, there are always bound to be errors.

I'm going to share a few different concepts and things I've stumbled across while building applications with Wind Surf and spending so many hours building these applications.

Some might be straightforward, or you might think they aren't necessary, but they really make a difference. Some of these are covered while building out the application earlier in the video, but we'll go through everything.

Starting off, we want to ensure we have a well-defined, clear instructions file and keep referring back to it constantly throughout the project.

This ensures the model is aware of the context of the project because if the chat window gets too loud, it starts forgetting what the project is about, hallucinating, and messing up the code.

Next, we split the features. As shown in the different instructions files, we want to split the features in a way that they build upon each other.

This allows us to build one task at a time, one feature at a time, test it, and ensure it works before moving on to the next one.

The third tip is adding documentation snippets into the instructions file. This helps improve accuracy, especially when we have different versions of documentation, and we want to pick a specific one.

This is always good practice to paste into the instructions file, ensuring we know exactly which version of a library we're building.

The fourth tip is breaking up the chat window. We want to start new conversations, re-explaining the instructions.

For every new chat we create, we want to refer back to the instructions file because every time we start a new window, Wind Surf won't have memory of what the project is.

We want to ensure we re-reference the instructions file.

Number five is keeping the app running. Wind Surf implements the code for you, making changes and updates.

Every time we make an update to the code, we can have the application running and test out the features we just added to ensure they work before going back to Wind Surf and accepting the changes.

Number six is straightforward: using the image upload feature that was just released for debugging purposes.

I showed you a demo of this earlier, and we can ask it for UI improvements or showcase a UI we like when starting a new project, asking it to build something similar.

Number seven is accepting parts of the generated code and rejecting others. We don't have to accept all the changes, and it's good practice to review the changes the model made to ensure it doesn't mess up the code.

If it starts touching parts of the code it shouldn't, you can reject those parts and accept everything else. This has saved me a lot of time.

For number eight, for any minor updates to the code, we want to add this at the end of the prompt. This helps ensure other parts of the code aren't changed.

By adding a simple sentence at the end, we can say, "Make sure to check the files before building anything. Do not mess up any of the existing functionality," especially when starting a new chat.

This seems to minimize hallucinations.

Number nine: after completing and testing every feature, we want to commit the changes to GitHub. This acts as a save checkpoint, so if we mess up the code completely, we can always refer back to a safe state of the application.

Finally, when facing errors and you're bashing your head against the wall, asking Wind Surf to fix errors back and forth without success, I've always referred back to ChatGPT's model.

I give it the code, say, "This is my code, this is what I'm trying to do, and these are the errors I'm getting." It's a simple prompt, and I send that, and every time, it manages to fix the problem.

Keep that in mind.

That will be the end of the Wind Surf masterclass. I hope you found this helpful. It's an exciting time to be in the AI space right now, especially if you're an AI agency owner.

You can see the power of this technology; you can start building applications for your clients and have something tangible instead of just automations and workflows in the backend.

You can present something nice to your clients, and I'm excited to use Wind Surf more and carry on building.

If you have any ideas, drop them in the comments below. If you're a business owner or have an idea you'd like to build and want to work with us, I'll put the link to my calendar down below.

Feel free to reach out, and we can hop on a call to discuss how we can help you. If you want access to the masterclass document or the complete code, I'll be putting that inside my school community, so I'll link that down in the description below.

If you found this helpful, please hit that like and subscribe button.

With that being said, thank you very much, and I'll see you in the next one!