<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Juan Carlos Padillo</title>
    <description>The latest articles on Forem by Juan Carlos Padillo (@onlypads).</description>
    <link>https://forem.com/onlypads</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1270842%2Fd9b9db3e-7c47-464d-9e81-aab5e9c67275.png</url>
      <title>Forem: Juan Carlos Padillo</title>
      <link>https://forem.com/onlypads</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/onlypads"/>
    <language>en</language>
    <item>
      <title>Building Team Invitations in Laravel</title>
      <dc:creator>Juan Carlos Padillo</dc:creator>
      <pubDate>Sat, 02 May 2026 14:29:12 +0000</pubDate>
      <link>https://forem.com/onlypads/building-team-invitations-in-laravel-306g</link>
      <guid>https://forem.com/onlypads/building-team-invitations-in-laravel-306g</guid>
      <description>&lt;p&gt;Today I finished the invitation flow for my team task management project.&lt;/p&gt;

&lt;p&gt;At first, the feature looked simple: invite a user by email and let them join a team. But once I started building it, I realized there were a few real-world cases to handle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the invitation flow does
&lt;/h2&gt;

&lt;p&gt;A team owner can invite someone using their email address.&lt;/p&gt;

&lt;p&gt;When an invitation is sent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the system checks if the user is already a team member&lt;/li&gt;
&lt;li&gt;it checks if there is already a pending invitation for that same email in that team&lt;/li&gt;
&lt;li&gt;if everything is valid, an invitation record is created with a token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the invited user accepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the system verifies the logged-in user matches the invited email&lt;/li&gt;
&lt;li&gt;the user gets attached to the team&lt;/li&gt;
&lt;li&gt;the invitation gets deleted&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;The biggest lesson was learning where code should live.&lt;/p&gt;

&lt;p&gt;My controller worked, but it started getting crowded fast. It was handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;duplicate checks&lt;/li&gt;
&lt;li&gt;member checks&lt;/li&gt;
&lt;li&gt;creating invitations&lt;/li&gt;
&lt;li&gt;attaching users to teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That pushed me to move the business logic into service classes.&lt;/p&gt;

&lt;p&gt;Now the controller mostly handles the request and delegates the actual work.&lt;/p&gt;

&lt;p&gt;That small refactor made the code much easier to read.&lt;/p&gt;

&lt;p&gt;Check out the difference in the controller after using service classes.&lt;/p&gt;

&lt;p&gt;Here’s the code for storing an invitation that I originally wrote without using a service class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp0r81majf6iluxbps5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp0r81majf6iluxbps5f.png" alt="Controller for storing invitation" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s a lot going on in this method, and I even duplicated &lt;code&gt;Invitation::create()&lt;/code&gt;—that’s on me. 😅&lt;/p&gt;

&lt;p&gt;Here’s the same method refactored using a service class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk47lsi583fcx6hvr4fec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk47lsi583fcx6hvr4fec.png" alt="Store method with service class" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's much cleaner and easier to read. I also created Form Request class, so input validation is handled in a separate class.&lt;/p&gt;

&lt;h2&gt;
  
  
  One small bug that taught me something
&lt;/h2&gt;

&lt;p&gt;I got stuck for a while checking duplicate invitations.&lt;/p&gt;

&lt;p&gt;At first I used &lt;code&gt;get()&lt;/code&gt;, which returns a collection. Even when empty, it still caused confusing behavior.&lt;/p&gt;

&lt;p&gt;Switching to &lt;code&gt;exists()&lt;/code&gt; made the intent much clearer.&lt;/p&gt;

&lt;p&gt;That was a small thing, but it helped me understand Eloquent a little better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;The invitation system is working now, and the project is starting to feel like a real application instead of just practice.&lt;/p&gt;

&lt;p&gt;Next, I’m focusing on the frontend, starting with a cleaner dashboard and better team/project pages.&lt;/p&gt;

&lt;p&gt;Github repo: &lt;a href="https://github.com/pads-only/team-task-manager" rel="noopener noreferrer"&gt;Team Task Manager&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I’m using ChatGPT as part of my learning process—to sanity-check ideas, understand Laravel patterns, and think through tradeoffs. I still write the code myself and use the project to test whether I actually understand what I’m building.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>laravel</category>
      <category>programming</category>
      <category>learning</category>
    </item>
    <item>
      <title>Building Teams in Laravel (Ownership &amp; Membership)</title>
      <dc:creator>Juan Carlos Padillo</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:40:25 +0000</pubDate>
      <link>https://forem.com/onlypads/building-teams-in-laravel-ownership-membership-5bg1</link>
      <guid>https://forem.com/onlypads/building-teams-in-laravel-ownership-membership-5bg1</guid>
      <description>&lt;p&gt;After setting up the basic structure of my project, I implemented the team creation flow.&lt;/p&gt;

&lt;p&gt;The idea is simple: a registered user can create a team and immediately become both the owner and a member of that team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key decision
&lt;/h2&gt;

&lt;p&gt;I separated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ownership → stored in &lt;code&gt;teams.owner&lt;/code&gt;_id&lt;/li&gt;
&lt;li&gt;membership → stored in &lt;code&gt;team_user&lt;/code&gt; pivot table&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows flexibility where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a user can belong to multiple teams&lt;/li&gt;
&lt;li&gt;roles can be managed per team&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;When registered user create a team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new team is stored with &lt;code&gt;owner_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The user is attached to &lt;code&gt;team_user&lt;/code&gt; with role = &lt;code&gt;owner&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures the creator is automatically part of the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Instead of treating the owner separately, I treat them as a member with elevated permissions&lt;/p&gt;

&lt;p&gt;This keeps relationships consistent and simplifies access control later.&lt;/p&gt;

&lt;p&gt;Next, I’ll implement the invitation system so team owners can invite other users and build actual collaboration.&lt;/p&gt;

&lt;p&gt;Github repo: &lt;a href="https://github.com/pads-only/team-task-manager" rel="noopener noreferrer"&gt;https://github.com/pads-only/team-task-manager&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>learning</category>
      <category>backend</category>
    </item>
    <item>
      <title>Building a Laravel Team Task Manager from Scratch (Planning &amp; System Design)</title>
      <dc:creator>Juan Carlos Padillo</dc:creator>
      <pubDate>Tue, 28 Apr 2026 15:41:21 +0000</pubDate>
      <link>https://forem.com/onlypads/building-a-laravel-team-task-manager-from-scratch-planning-system-design-45c6</link>
      <guid>https://forem.com/onlypads/building-a-laravel-team-task-manager-from-scratch-planning-system-design-45c6</guid>
      <description>&lt;p&gt;Hello, I’m starting a new project to improve my backend development skills using Laravel.&lt;/p&gt;

&lt;p&gt;The goal is to build a Team Task Management System that simulates real-world collaboration, similar to tools like Trello or Asana, but simplified and focused on learning backend architecture.&lt;/p&gt;

&lt;p&gt;This post is the first in a series where I’ll document the entire development process, from planning to deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Goal
&lt;/h2&gt;

&lt;p&gt;The system allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users and Teams&lt;/li&gt;
&lt;li&gt;Projects inside teams&lt;/li&gt;
&lt;li&gt;Tasks inside projects&lt;/li&gt;
&lt;li&gt;Task assignments, comments, and attachments&lt;/li&gt;
&lt;li&gt;Notifications for updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why am I Building This
&lt;/h2&gt;

&lt;p&gt;I want to go beyond the CRUD basic apps and focus on real-world backend concepts like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eloquent relationships&lt;/li&gt;
&lt;li&gt;Policies and authorization&lt;/li&gt;
&lt;li&gt;REST API design&lt;/li&gt;
&lt;li&gt;Service classes&lt;/li&gt;
&lt;li&gt;Queues and notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  High-level idea
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A user joins a team via invitation&lt;/li&gt;
&lt;li&gt;Teams manage multiple projects&lt;/li&gt;
&lt;li&gt;Projects contain tasks&lt;/li&gt;
&lt;li&gt;Tasks can be assigned, discussed, and tracked&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Database planning
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;users&lt;/li&gt;
&lt;li&gt;teams&lt;/li&gt;
&lt;li&gt;team_user&lt;/li&gt;
&lt;li&gt;invitations&lt;/li&gt;
&lt;li&gt;projects&lt;/li&gt;
&lt;li&gt;tasks&lt;/li&gt;
&lt;li&gt;task_user&lt;/li&gt;
&lt;li&gt;comments&lt;/li&gt;
&lt;li&gt;attachments&lt;/li&gt;
&lt;li&gt;notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next step
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Laravel Breeze setup&lt;/li&gt;
&lt;li&gt;Database migrations&lt;/li&gt;
&lt;li&gt;Team and user relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it for the planning phase. See you in my next blog post!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>learning</category>
      <category>backend</category>
      <category>laravel</category>
    </item>
  </channel>
</rss>
