<?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>DEV Community: Kamran Khan</title>
    <description>The latest articles on DEV Community by Kamran Khan (@kamrankhandev).</description>
    <link>https://dev.to/kamrankhandev</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4173976%2Fb63d809a-a6c7-4508-becb-3a54f7d2c6c3.png</url>
      <title>DEV Community: Kamran Khan</title>
      <link>https://dev.to/kamrankhandev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kamrankhandev"/>
    <language>en</language>
    <item>
      <title>5 Laravel API conventions that save you a week on every project</title>
      <dc:creator>Kamran Khan</dc:creator>
      <pubDate>Sat, 10 Oct 2026 01:48:50 +0000</pubDate>
      <link>https://dev.to/kamrankhandev/5-laravel-api-conventions-that-save-you-a-week-on-every-project-59l4</link>
      <guid>https://dev.to/kamrankhandev/5-laravel-api-conventions-that-save-you-a-week-on-every-project-59l4</guid>
      <description>&lt;h1&gt;
  
  
  5 Laravel API conventions that save you a week on every project
&lt;/h1&gt;

&lt;p&gt;Every client project I take on used to start the same way: a day wiring up auth, another day on roles and validation, a third day arguing with myself about response shapes. After the third project I extracted the patterns into a starter kit and stopped paying that tax. Here are the five conventions that did the most work.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. One auth controller, kept boring
&lt;/h2&gt;

&lt;p&gt;All authentication lives in a single &lt;code&gt;Api/AuthController&lt;/code&gt; with exactly four methods: &lt;code&gt;register&lt;/code&gt;, &lt;code&gt;login&lt;/code&gt;, &lt;code&gt;logout&lt;/code&gt;, &lt;code&gt;me&lt;/code&gt;. Tokens come from Laravel Sanctum — &lt;code&gt;createToken('auth-token')-&amp;gt;plainTextToken&lt;/code&gt; — and that's it. No Passport, no OAuth dance, no JWT package to maintain.&lt;/p&gt;

&lt;p&gt;The auth layer is isolated in one controller, so if you ever outgrow Sanctum you're swapping one file, not rewiring the app. (Honest note: there's no password reset or email verification wired up yet — the User model has the &lt;code&gt;MustVerifyEmail&lt;/code&gt; import stubbed and commented, ready for you to enable when you need it.)&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Validation lives in FormRequest classes, never in controllers
&lt;/h2&gt;

&lt;p&gt;Every endpoint validates through a dedicated FormRequest. Controllers stay thin and readable. One place per endpoint where the rules live. When the frontend team asks "what does this endpoint accept?", the answer is a single file, not a hunt through controller logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. API Resources shape every response
&lt;/h2&gt;

&lt;p&gt;No endpoint ever returns a raw model. A &lt;code&gt;UserResource&lt;/code&gt; decides exactly what the client sees — id, name, email, role, timestamps. This is the difference between "it works" and "it's safe" — no password hashes or remember tokens ever leaking because someone returned &lt;code&gt;$user&lt;/code&gt; directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Roles without the ceremony
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;role&lt;/code&gt; string column on the users table (default &lt;code&gt;'user'&lt;/code&gt;) plus one tiny middleware covers 90% of SaaS needs. Aliased as &lt;code&gt;'role'&lt;/code&gt;, used like &lt;code&gt;Route::middleware(['auth:sanctum', 'role:admin'])&lt;/code&gt;. And one detail that matters: registration hardcodes &lt;code&gt;'role' =&amp;gt; 'user'&lt;/code&gt; — the role can never be self-assigned through the public endpoint. I didn't pull in a full permissions package on day one. That's a week-two problem, and bolting it on later is easy when the middleware pattern is already there.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Routes grouped by who can touch them
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;routes/api.php&lt;/code&gt; reads like an access-control document: public auth endpoints, authenticated endpoints, admin-only endpoints. Three groups. A new developer can see the entire security model of the API in thirty seconds.&lt;/p&gt;




&lt;p&gt;None of this is exotic. That's the point — these are the unglamorous decisions that turn "week zero" from five days into an afternoon. I packaged all of them, plus a React dashboard frontend wired to this API, into a starter kit because I was tired of rebuilding it on every project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Laravel + React SaaS Starter Kit — $19, one-time:&lt;/strong&gt; &lt;a href="https://kamranofficial.gumroad.com/l/mhekoig" rel="noopener noreferrer"&gt;https://kamranofficial.gumroad.com/l/mhekoig&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Questions about any of these conventions? Drop a comment — happy to dig in.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React dashboard architecture: how I organize a real SaaS frontend</title>
      <dc:creator>Kamran Khan</dc:creator>
      <pubDate>Sat, 10 Oct 2026 01:48:24 +0000</pubDate>
      <link>https://dev.to/kamrankhandev/react-dashboard-architecture-how-i-organize-a-real-saas-frontend-h0p</link>
      <guid>https://dev.to/kamrankhandev/react-dashboard-architecture-how-i-organize-a-real-saas-frontend-h0p</guid>
      <description>&lt;h1&gt;
  
  
  React dashboard architecture: how I organize a real SaaS frontend
&lt;/h1&gt;

&lt;p&gt;I've inherited too many React frontends where fetch calls were scattered across components, tokens were read from localStorage in twelve places, and adding one protected page meant touching five files. When I built the frontend for my SaaS starter kit, I set five structural rules. Here's how they work, with the real code.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. One API client module — components never touch HTTP directly
&lt;/h2&gt;

&lt;p&gt;Everything goes through a single axios instance in &lt;code&gt;src/api/client.js&lt;/code&gt;: base URL from env, a request interceptor attaching the Bearer token from localStorage, and a response interceptor that on 401 clears the token and redirects to &lt;code&gt;/login&lt;/code&gt; (skipping &lt;code&gt;/login&lt;/code&gt; and &lt;code&gt;/register&lt;/code&gt; themselves). Base URL from env, token attached automatically, expired sessions handled globally. When an endpoint changes, you edit one file. Components import this client and call it — they never construct URLs or headers themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Auth state lives in one context
&lt;/h2&gt;

&lt;p&gt;A single &lt;code&gt;AuthContext&lt;/code&gt; owns the session: user, token, loading state, and &lt;code&gt;login&lt;/code&gt;/&lt;code&gt;register&lt;/code&gt;/&lt;code&gt;logout&lt;/code&gt; functions. On mount it restores the session from the stored token. Logout is best-effort by design — the session is cleared locally no matter what the server says. No component ever reads &lt;code&gt;localStorage&lt;/code&gt; directly. If you change how sessions work, there's exactly one place to change it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Route guards, not scattered checks
&lt;/h2&gt;

&lt;p&gt;Protected pages are wrapped, not conditionally rendered inside page components: a &lt;code&gt;ProtectedRoute&lt;/code&gt; that shows a spinner while loading and redirects to &lt;code&gt;/login&lt;/code&gt; without a session, plus an &lt;code&gt;AdminRoute&lt;/code&gt; adding a role check. The loading state matters more than people think — without it, the app flashes the login page on every refresh while the session restores.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Layout is a component, pages are just content
&lt;/h2&gt;

&lt;p&gt;The dashboard shell — sidebar, topbar, content area — is a single &lt;code&gt;Layout&lt;/code&gt; component. New pages are just content dropped into it. Adding a settings page means writing the settings content, not rebuilding navigation for the tenth time.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Demo mode that doesn't pollute the real code
&lt;/h2&gt;

&lt;p&gt;The kit ships with a clickable demo that runs without a backend. The trick is a seam in exactly one place: &lt;code&gt;const client = isDemoMode() ? createDemoClient() : axios.create({ ... })&lt;/code&gt;. A &lt;code&gt;demoMock.js&lt;/code&gt; implements the same interface against in-memory data. The rest of the app can't tell the difference. One conditional at the client boundary, zero demo hacks scattered through the UI.&lt;/p&gt;




&lt;p&gt;Boring on purpose. Every file has one job, and a new developer can map the whole frontend in an afternoon.&lt;/p&gt;

&lt;p&gt;I packaged this frontend together with its Laravel API backend — Sanctum auth, roles, REST conventions, seeders — into a starter kit, because rebuilding this setup on every project was costing me a week each time:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Laravel + React SaaS Starter Kit — $19, one-time:&lt;/strong&gt; &lt;a href="https://kamranofficial.gumroad.com/l/mhekoig" rel="noopener noreferrer"&gt;https://kamranofficial.gumroad.com/l/mhekoig&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What would you organize differently? Genuinely curious — drop a comment.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>saas</category>
    </item>
    <item>
      <title>How I Structured My Laravel + React SaaS Starter Kit</title>
      <dc:creator>Kamran Khan</dc:creator>
      <pubDate>Fri, 09 Oct 2026 18:54:02 +0000</pubDate>
      <link>https://dev.to/kamrankhandev/how-i-structured-my-laravel-react-saas-starter-kit-12ek</link>
      <guid>https://dev.to/kamrankhandev/how-i-structured-my-laravel-react-saas-starter-kit-12ek</guid>
      <description>&lt;p&gt;Every SaaS project I take on starts with the same unglamorous week: authentication, user roles, a settings page, a dashboard shell, and arguing with myself about API response shapes. On my third client project I stopped copy-pasting from old repos and built the setup properly — once. This is how it's structured.&lt;/p&gt;

&lt;h2&gt;
  
  
  The split: API backend, SPA frontend
&lt;/h2&gt;

&lt;p&gt;The reason is practical: sooner or later a dedicated frontend dev touches the project, and a clean API boundary makes that handoff painless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth: Sanctum, kept boring
&lt;/h2&gt;

&lt;p&gt;Laravel Sanctum with token-based auth. Login, register, logout, and a /me endpoint — the standard Sanctum token flow. Password reset and email verification aren't wired up yet (the User model has the MustVerifyEmail import stubbed and commented, ready for you to enable), so the auth surface stays small and honest. I chose Sanctum over Passport deliberately: for a typical SaaS the token flow is simpler and there's less machinery to maintain. The auth layer is isolated, so if you ever outgrow it, you're swapping one controller and a middleware, not rewiring the app.&lt;/p&gt;

&lt;p&gt;On the React side, a single axios instance handles everything: base URL from env, an interceptor attaching the token, and a 401 interceptor that clears the session and redirects to login. Auth state lives in one context — components never touch tokens directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  API conventions: one envelope, no guessing
&lt;/h2&gt;

&lt;p&gt;Responses are plain, predictable Laravel JSON — auth returns the user resource plus the token, and validation errors use Laravel's standard shape keyed by field, which maps 1:1 onto frontend form validation. I kept the response shapes boring on purpose: no custom envelope to learn, no guessing what an endpoint returns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles without the ceremony
&lt;/h2&gt;

&lt;p&gt;A simple &lt;code&gt;role&lt;/code&gt; column plus a middleware covers 90% of SaaS needs. The kit ships with &lt;code&gt;admin&lt;/code&gt; and &lt;code&gt;user&lt;/code&gt; roles and a seeder so you can log in as either immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  The React API layer
&lt;/h2&gt;

&lt;p&gt;API access lives in one place — src/api/client.js, a single Axios instance with a token interceptor and a 401 interceptor that clears the session and redirects to login. Components and hooks go through this client; they never construct URLs or headers by hand. When an endpoint changes, you edit one file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Billing: bring your own Stripe
&lt;/h2&gt;

&lt;p&gt;There's no billing code in the kit — no subscriptions table, no webhooks, no Stripe SDK. That's deliberate: I've seen too many projects drag in payment machinery before they have a single user. When you're ready to charge, Laravel Cashier plus a subscriptions migration slots straight into the auth and user scaffolding that's already here.&lt;/p&gt;




&lt;p&gt;I packaged all of this into a starter kit because I was tired of rebuilding it. If you'd rather skip week zero and start on your actual product, it's here:&lt;br&gt;
&lt;strong&gt;Laravel + React SaaS Starter Kit — $19, one-time:&lt;/strong&gt; &lt;a href="https://kamranofficial.gumroad.com/l/mhekoig" rel="noopener noreferrer"&gt;https://kamranofficial.gumroad.com/l/mhekoig&lt;/a&gt;&lt;br&gt;
Questions about any of the structural choices? Drop a comment — happy to dig in.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>react</category>
      <category>saas</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
