Laravel 13 Teams CRUD: The Complete Step-by-Step Guide (2026)
Chapters11
Intro to the idea of building a Laravel Inertia React app with teams and using AI to generate code, followed by handcrafting the project.
A practical, hands-on Laravel 13 Teams CRUD guide using Inertia + React, showing step-by-step setup, models, policies, and UI for team-scoped posts.
Summary
Tony Xhepa walks through building a Laravel 13 project labeled as a “Teams CRUD” app, focused on multi-tenant-style posts tied to teams. He starts from a fresh Laravel project with the Inertia React starter kit, then creates a Post model, migration, policy, and a resource controller. The tutorial covers routing under a current team, post listing with author data, and the create/edit/delete flows driven by a robust policy that checks team membership. Along the way, he reinforces practical details like using a Team scope in Eloquent queries, wiring up front-end components (Post index/create/edit) in TypeScript, and extending the UI with a custom TextArea component. The video emphasizes real-world considerations: naming the author field as a distinct relation, updating the post with a slug and ID, and safeguarding actions with gates (view/create/update/delete). Finally, Tony demonstrates live on the Inertia app how a team member can create multiple posts, see feature posts, and manage posts with permission checks. If you’re aiming to build a team-centric CMS with Laravel 13, Inertia, and React, this walkthrough translates the theory into a working scaffold the moment you finish watching.
Key Takeaways
- Create a Laravel 13 project using the Inertia React starter kit and set up a Teams scaffold before building the Post resource.
- Define a Post model with team_id, user_id (author), title, and body, and establish belongsTo relationships to Team and Author (renaming the user relation to author).
- Implement a PostPolicy that allows viewing if the user belongs to the post's team, creation for all authenticated users, and updates/deletes based on user_id matching the post's user_id.
- Route posts under the current team (route prefix current_team) and implement a resource controller with index, create, store, edit, update, and destroy actions.
- Create a dedicated TypeScript front-end (via TSX) for Post index/create/edit and wire Inertia routes to a typed Post interface for safer UI code.
- Add a reusable TextArea component in the front-end to support the post body field and ensure the create/edit forms post to the correct team slug.
- Demonstrate live UI behavior: feature post display, per-post edit/delete buttons conditioned on permissions, and navigation between index/create/edit pages.
Who Is This For?
This is essential viewing for Laravel developers who want to implement team-scoped resources with Inertia + React. It’s especially helpful for those building a multi-tenant-like CMS where posts belong to teams and permissions must be enforced on both back-end and front-end layers.
Notable Quotes
"So we are going to create the same project by hand. So we are going to use React with Inertia starter kit and then add post model and migration."
—Tony explains the plan to build the project manually using the Inertia + React kit and then add the Post model.
"The relationship with the user and the team ID is crucial. We need the team ID, user ID, title, and body."
—Describes the core fields in the Post model and their relationships.
"If the user belongs to the team and we get post team here, it will return true for view."
—Covers the PostPolicy view logic based on team membership.
"We are going to return inertia render post index and pass the current team so the UI knows which team we’re working with."
—Shows how routing and Inertia props are wired for team-scoped listing.
"The front-end uses a typed Post interface and a TSX file structure to keep the code safe as you grow."
—Highlights the TypeScript typings used for the Post data in the UI.
Questions This Video Answers
- How do you implement team-scoped resources in Laravel 13 with Inertia and React?
- What is the proper way to model a Post with team_id and author in Laravel?
- How can I enforce policies for viewing, creating, updating, and deleting posts by team membership?
- How do you wire Inertia routes under a current_team prefix in Laravel?
- What are best practices for building a React + TypeScript front-end for Laravel Inertia pages (index/create/edit)?
Laravel 13Laravel InertiaReact Starter KitTeam-based permissionsPost model and migrationPostPolicyTeam routesResource controllerEloquent relationshipsTypeScript with Inertia
Full Transcript
Hello friends, Sony here. Welcome. So in the previous video, I created this project. No, I demoed this project. And yeah, I had some comments that uh I just demo the project. I don't show any code. And the idea was just to show you just to demo this project and then you with the AI with the help of the AI you can ask the to build something like this. Okay. Okay. So you just have the idea here and you say the right cloud code for example create something like this or also you can uh screenshot the project and paste a screenshot on the cloud code and ask to generate something and of course the cloud code is going to do the best not maybe 100% but almost the same as this one but in this video because I had the comments I'm going to create the same project by hand.
So we are going to create step by step and what we need here is just to create a lar project with the teams and we're going to use react with inertia starter kit and then add post model and migration and yeah we need to create a index page for post to display all the posts also new page for the create to create a post and also the edit. So let's start by creating a Laravel project. Here I'm going to say Laravel. Uh and I'm going to create let's say inertia teams. I'm going to choose React and I'm going to add teams here.
I'm not going to run the mpm installed for now because I'm going to run the composer around def when I'm going to open the project. Okay. Okay. So let's see the the inertia of uh teams going to paste it here. I'm going to clean and let's make the post model first. So PHP align make model and the name is endb post and what we need here is the form request the migration also the policy because not everyone who can see the post can update that and delete resource controller and that's it with the create. Okay.
And let's open this with the code editor of all choice. And let's run the mpm install and also the composer rundev. If I go with the env file, we have inertia teams. I'm going to go down there when we have yeah for the database I'm going to use suite. Then for the mail I'm going to use the mainstrap. And if you go and create a misrap go to my inbox and for example here on the code samples we have also the Laravel and I'm going to choose Laravel 9 plus because we have Laravel 13 and I'm going to paste that one here.
Okay, let's close. Next, let's open the post migration. And what we need here the relationship with the user and the team ID. So let me just paste the code here. Table for ID for the team ID constraint on cascade on delete and also for the user ID and then add the title and the body. Okay. Next let's run the composer not the PHP artisan migrate fresh. Yeah, we can run the migrate fresh. And now let's open the post model. And here I'm going to add first the field label. And what we need is the team ID, user ID, the title, and the body.
Then let's create the relationship for the team and for the user. So public function user or let's create first the team and this is going to be a belongs to relationship and let's return here this belongs to team class. Next let's create the user belongs to relationship and return this user but the user I'm going to name it uh different. So instead of user I'm going to name it author and because I named different I'm going to add also here the user ID as a foreign key. I think we are good here. Let's open because we are here.
Let's open also the user model. We don't need in this one but I'm going to open the user model and create a relationship for post. So public function post and this is going to be a has many relationship and let's return has many posts class and the same thing we can do also on the team model. I'll scroll down and let's create a for the post also here this is a has many and we can return has many posts okay let's close also here let's close because we are good and let's open the web routes I'm going to register the route in here so route prefix current theme because when we are on the dashboard and on the post you can see we have the team first and then the post.
So inside the current team we have this inertia for the dashboard. Let's create another route now not inertia but I'm going to say route resource for post and using the post controller I think. Yeah we have imported the post controller here. Very good. Now let's open the post controller and we have the index method. We are not going to get all the posts because we need the post from the team. Okay. So for that we need to receive here the request total sign request and also the team and I'm going to name it yeah we can name it team or current team.
Let's name it current team. And we need to import this model. And then I'm going to get the post like this. So post where the team ID is current team ID with the author there. We created the relationship author. So author we need only the ID and the name. lat test get and we're going to make a map function here and display the ID title body author to be this post author name and then the create and here I'm going to add also a can and on the can I'm going to add an array with edit and delete and here saying request user can update passenger post and request user can delete pass in the post because we have the post policy so let's open that post policy You see and for the view any I'm going to turn this to be true so anyone can view the list of polls but for the view here I'm going to say not return false but I'm going to say return if dollar sign user can view or in my case it's going to be belongs to team because if the user pass in here post team we have the relationship and we need the team like this.
So if the user belongs to team and we get post team here if that is okay it's going to return true and then the user can view that post. Okay, for the create I'm going to return that true. So every user can create a post for the update where to say if dollar sign user ID is triple the dollar sign post user ID. Okay. And the same thing I'm going to do also for the delete. Then we have the restore but I'm going to leave it like this. False and false. Okay. So we get the post.
Now let's return. We need to return here. And we're going to return the inertia render post index. And here we have to pass a post. But the post index is not with a capital P but lower P and index. And let me just create the resources JS pages. We have themes. Now let's create also here first a directory for the post. And then let's create a new file which going to be index.tsx. And also this one to save as create.ts. tsx and save as edit.tsx. So here's going to be the create the index sorry create and edit.
Let's start and yeah now we don't have underline error. Let's remove that on the create. What we need is just the return inertia render post create. Okay. Then we have a store. Let's open this store post request. Change the authorize here return to be true. And I'm going to scroll down and add the rules. We need the title to be required and we need the body. And I'm going to close. We need the request here and also the team quantity. And we are going to return a red direct response, not just a response. See use response and let's say dollar sign post able with post create pass in the request validated but we need to add here also the user and the user ID and the current team ID.
So instead of this we can add an array distract here the request validated which mean we're going to add the title and the body and then after the title and the body I will add also the team ID and I will add also the bo not the body but the user the user ID And let me just uh indent like this request user ID. Okay. Then we need to return. So let's say return and not redirect but we return to the route not post index. In many times I return redirect to the post index. But because in the previous video we return the edit.
So we have to say the post edit pass in the post here. Okay. So post controller at ededit and I'm going to remove the show. So which mean where to return in here in the edit but before the post we to receive also the current team because that is the first slack. Okay, here we have the current theme, then post, then slash, and the ID of the post. So, first we get the team model and I'm going to name it current team. And yeah, also because we added here the post, we need to add also the current team.
So, let's dollar sign current team also. So quent team and the post qu team and the post and first we're going to use the gate support facade gate authorize update but I don't want to add update what I want to add is let's open again the post policy and here on the view return user belongs to team pass in the post team so I'm going to turn instead of using the update the only the user ID is repable with the post user ID I'm going to say here when we go to edit get authorize view so the user who belongs to the team can view that edit page but we are going to not show the uh delete and update post we're going just to show the post but not the buttons Okay, that's the idea.
And here we need to return inertia render post edit. But I'm going to add post with an array with ID title body and then can edit and delete which is going to come from the request user. So also we need the to receive the request here. So request dollar sign request. So can edit if the user can update the post and delete if the user can delete the post. Okay, next we have the update. So let's open this change the true and then scroll down also validate the title and the body. And here also we need the quant team.
So let's say team dollar sign current team. Now you can use team here but I prefer to use the current theme. And first use the gate authorize update pass in the post then post update dollar sign request validated just not inside the array outside the array. And then we need to return to that post edit pass in the current team and post. And to be more precise I we need to add here the slug. And also on the post we need to add the ID. And the same thing we can do also up here. We need to do up here where we return.
Yeah. slug and ID and we need to return here redirect response. Okay, scroll down destroy also here we need the current team. So let's say team dollar sign current team and here it's going to return a redirect response. We are going to use gate to authorize the delete then delete and then return to the route post index and on the post index also we need to add the current team slit. Let's return a response here. Inertia response also on the index we need to return inertia response. Now let's start and work with the index. Here I'm going to paste the code because it's going to take us time to write by ourself.
import head link router use page from the inertia js/react and also import some uh icons import heading badge button dashboard and also import the create destroy edit and index from the routes post yeah we don't have a post type so let's go and create a type for the post which mean inside the types so in resources js we have types and we have the index Here we have export type out navigation team themes. So let's go and create a new file also here and the name of the file is going to be post.ts and here I'm going to add export type post with ID title body out created out and also the can edit and delete which is our boolean.
Let's close this. And here now let's also say export type all from slash post and let's close this. And now we are okay with post type props post pass in here post array type. Then here is if you want if you don't like if you want only to display a table with post you don't need this but because I created on the previous video I as the writer creates a function for the word count returning a number passing your receiving a string and return text split filter boolean length. Okay. Then excerpt if post body length is smaller or equal with this mark length is going to return post body otherwise going to return post body slice.
Then we have the export default function post index which going to receive post which is a type of this props which we have up here. Okay. Then we to create a cons for the quent team where they use the use page and distract the quent team only also current uh feature post because we have feature post and also the remaining post from the post where we distract an array from the post. Get the feature post which to be the last one and also the remaining post label post length post. If the post length is one, we have to say just post.
Otherwise, we have to say post with s at the end. Also, total words, average words and delete post. We have to confirm first if confirm delete passing the post title with say router delete destroy URL passing the current team slug and the post ID. And then we have the HTML head post uh with section and so on. We have a batch for the so let me just show you team publishing is here and maybe zoom it a bit. Okay. Then we have a heading with title post like this and yeah keep announcements which is this.
Here we have a link with plus icon. New post. Navigate to the create URL. Pass in the current team slack on that create URL. Okay, this one new post. Then we have the library contributors and average length. So grid here with a grid with a gap three and grid calls three library post label contributors and here we use new set post map post post author size. Okay. And also the average length using the average words. If that is greater than zero we're going to add average words. Otherwise, we to say no draft yet. As you can see, we have no draft yet.
Okay. Then if the post length is triple width zero, we to say uh your editorial space is empty. So no post yet. Otherwise, yeah, we to say we're going to add also the link here to create the first post. Otherwise, we're going to add a grid. And first, we'll display if we have a feature post, we have to display that feature post. So, let's me just go and create a new post here. Go back to post. Yeah, this is a feature Display that. So create a link TF edit URL feature post max length 260 author.
So display also the author here words and then we say if the featured post can edit if the user can edit because we have on the edit on the index return with the can edit and delete and send request user can update and delete. Okay, if that can edit where the display a link edit URL current team slug and feature post ID and also for the delete otherwise if we don't have that feature post we display a null that is the latest entries and the same thing where they say post map display all the post adding the author created that and also edit URL and post can edit the same if the user can edit add the link for the edit and the link for the delete and that's it.
Yeah, also we have your post index layout pass in props quarantine slug name or null and breadcrumbs title dashboard and chef props current team. If we have where to say dashboard pass in the props quant team slug otherwise just slash and for the title post chef props quant team if we have quant team index pass in the props quant team slug otherwise just hash and that's it for the index now let's go to create and also here I'm I have prepared so I'm going just to paste that code we have imported all the components we need but we don't have this text area in the components UI text area in our project.
So let's go to components js components UI and here we need to create a new file which is going to be a text area.tsx tsx and here I prepared the code. So I'm going to just paste it here. We import all as react from react import also the CN from the lip utils and function test area pass in the class class name and props and this is the text area here. Okay export here text area and then we are good with a text area here. Then we have a export default function post create distracting the quant team from the use page.
And then we have the HTML new post a button to go back to post. And then we have a heading and the form using the store form passing the qu team sl. And we have the label and the input for the title body and the button for the create. So publishing publish the post and also a button to go back. So cancel and the same thing we have also post create layout pass in the dashboard post and pal just hash here then let's go to edit and let's just close this I'm going to paste also here the code and when we have imported everything here import the text area also I think I created the text area text area tsx.
Okay, I think we have run Yeah, composer rundev also here. And then we have a type of props. We have imported the destroy edit index and update from the narrow post. And we have the post edit function which we receive the post because on the post controller on the edit we return here the post. And then we have also this delete post method where the confirm first and then where to say router delete destroy URL current team slug and the post ID. We have the HTML. the uh button to go back to post and then if post can edit we protect if that is true if the user can edit the post we going to use a form duct update form pass in the qu team sl ID the errors processing and recently successful and then we have the HTML label for title and input for the title and for the body and the button the save changes also the button to cancel the to go back to index URL transition and then we have also here the delete if the user can want to delete that post the same thing post edit layout pass in the coins team and the post here and breadcrumbs title shrev if we have a current team we're going to say dashboard pass in here the props current team slug otherwise just slash the same thing for post and title is going to be props post title or just edit post and chef if we have quant team we're going to say props edit URL pass in the props qu team sl ID I think we are good and we're going to see now we have run here the composer rundev which mean if I open here now this is the react Teams React.
But let's open the inertia teams. Here is the project. I'm going to zoom a little bit and I register create the account. Okay, first thing I forgot to add the link here and for that let me just open the app sidebar. Okay, we have imported here the dashboard from the routes. But I need to import the index and I'm going to import this as a post index from add slash routes slash post and then we have this page and dashboard URL. Let me just simplify this a little bit. So create a team page props current team as slug or null and dashboard URL.
If we have a team where say dashboard pass in the team slug otherwise just slash and here we have the n items let's add also here another one for the post. So title is going to be shrev is going to be now if we have a team is going to be post index pass in the team slug otherwise just hash and icon is not going to be layout grid but it's going to be a file text yeah file text and I think we are good let's Okay. Okay. So, here we have a pose. If I click on the pose, we have almost the same as here.
I think we need one more zoom. Yeah. Now, let's go and create a new post. If I click, we are on the personal team here. So, let's go. Yeah. Let's create a new post here. Okay. where to use fake filler. Go. We created a post. We are on the edit. We can save changes. Cancel and delete. So, let's go back. And here we have a post. Let's create a new post. Or let's create a new team first. And I'm going to name it example or inertia. Let's name it inertia. Create a team. And now we are there to teams.
And I'm going to invite a member here. Let's use a fake fus save. And let's copy this one or let's copy first the link here. And I'm going to open this project in a new browser. Paste that browser here. I'm going to register use a fake viewer. I'm going to zoom it to see. And then let's copy the the email here because I want to use that email in here. Okay, we have only the personal team. But if I go and copy the link here, we have sent with invitation and paste it. Right now, now we are on the inertia team.
Okay. If I go to post, we don't have any post. So let's see inertia themes. Go to post. We are the inertia. Let's create a new post. Okay. Go back to post. Here is the post. Very good. And yeah, we have also here new post. But I'm going to add a new post by this user. Now we have two posts and two contributors. And because we created this post, we can open the post here. Good. And we can delete. But I'm going to create a new Just show you. Go back. We have three posts. Two posts, two contributors.
And now if I hover it to this one because we created, we are going to Ryan here. As you can see, Ryan, Ryan, and Ryan here. We can edit and we can delete. But to this one, no. If I go back to Chrome, refresh this one. We just can see also this one we just can see. If I hover it because we have created that this one, we can edit this one. And that's it all about this video. What I wanted to show you an example stepby-step example of uh Laravel teams with inertia react and how we can create a grat and manage grat with teams and user belongs to that team.
Now if you like such a videos don't forget to subscribe to my channel like the video and see you in the next one. Thank you very much.
More from Tony Xhepa
Get daily recaps from
Tony Xhepa
AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.






