--- name: laravel-saas-scaffold description: Scaffold a new Laravel SaaS application with Inertia.js, React, TypeScript, Tailwind CSS, shadcn/ui, Pest, Filament admin, WorkOS auth, and Stripe billing. Use when creating a new Laravel project or SaaS app from scratch. --- # Laravel SaaS Scaffold ## Stack - **Backend:** Laravel 12 with PHP 8.2+ - **Frontend:** Inertia.js + React + TypeScript + Tailwind CSS v4 + Vite - **UI Components:** Radix UI primitives + shadcn/ui pattern (via `@radix-ui/react-*`) + Lucide React icons - **Testing:** Pest PHP (feature + unit) + Playwright (E2E) - **Admin:** Filament v3 with superadmin gate - **Auth:** WorkOS AuthKit via `workos/workos-php-laravel` - **Billing:** Laravel Cashier (Stripe) - **Code Style:** Laravel Pint ## Step 1: Create Laravel Project ```bash laravel new project-name cd project-name ``` Select Inertia + React + TypeScript + Pest when prompted. Laravel 12 uses the `laravel new` interactive installer by default. ## Step 2: Install Core Dependencies ### PHP ```bash composer require inertiajs/inertia-laravel workos/workos-php-laravel laravel/cashier filament/filament tightenco/ziggy composer require --dev pestphp/pest pestphp/pest-plugin-laravel larastan/larastan ``` ### Node Detect package manager: check for `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `bun.lockb` → bun, else → npm. ```bash npm install @inertiajs/react @headlessui/react lucide-react tailwind-merge npm install @radix-ui/react-avatar @radix-ui/react-checkbox @radix-ui/react-collapsible @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-navigation-menu @radix-ui/react-select @radix-ui/react-separator @radix-ui/react-slot @radix-ui/react-toggle @radix-ui/react-toggle-group @radix-ui/react-tooltip npm install -D @tailwindcss/vite @vitejs/plugin-react @types/react @types/react-dom babel-plugin-react-compiler eslint-plugin-react eslint-plugin-react-hooks prettier-plugin-tailwindcss ``` ## Step 3: Directory Structure ``` app/ ├── Http/Controllers/ │ ├── AuthController.php │ ├── DashboardController.php │ └── BillingController.php ├── Models/ │ └── User.php (add is_superadmin, HasApiTokens) ├── Enums/ │ └── PlanEnum.php └── Policies/ config/ ├── workos.php (vendor:publish) ├── cashier.php resources/js/ ├── app.tsx ├── ssr.tsx ├── components/ │ ├── ui/ (shadcn-style primitives) │ └── app-sidebar.tsx ├── layouts/ │ ├── app-layout.tsx │ └── auth-layout.tsx ├── pages/ │ ├── dashboard.tsx │ ├── Landing.tsx │ ├── Billing.tsx │ ├── Terms.tsx │ ├── Privacy.tsx │ └── settings/ │ └── profile.tsx └── types/ └── index.d.ts routes/ ├── web.php └── console.php tests/ ├── Feature/ │ ├── Auth/ │ ├── BillingTest.php │ ├── AdminPanelTest.php │ └── LegalPagesTest.php └── Unit/ ``` ## Step 4: Auth Setup (WorkOS) Publish config: `php artisan vendor:publish --provider="WorkOS\Laravel\WorkOSServiceProvider"` Add to `.env`: ``` WORKOS_API_KEY=sk_... WORKOS_CLIENT_ID=client_... WORKOS_REDIRECT_URI=http://localhost:8000/auth/callback ``` Create `AuthController` with login/callback/logout using SDK methods (never construct OAuth URLs manually). ## Step 5: Billing Setup (Cashier) ```bash php artisan cashier:install php artisan migrate ``` Create `PlanEnum` with tiers (e.g., Free, Pro, Business). Add plan check helpers to User model. Add to `.env`: ``` STRIPE_KEY=pk_... STRIPE_SECRET=sk_... STRIPE_WEBHOOK_SECRET=whsec_... ``` ## Step 6: Filament Admin Panel ```bash php artisan filament:install --panels ``` Gate superadmin access in `AppPanelProvider`: ```php ->authGuard('web') ->login() ->middleware([...]) ``` Add `is_superadmin` boolean column to users migration. Gate panel access: ```php public function canAccessPanel(Panel $panel): bool { return $this->is_superadmin; } ``` ## Step 7: Legal Pages Always create Terms of Service and Privacy Policy pages as Inertia pages: - `resources/js/pages/Terms.tsx` - `resources/js/pages/Privacy.tsx` - Add routes and footer links ## Step 8: Herd/Valet Dev Setup Assign a unique Vite port per project to run multiple projects simultaneously: ```js // vite.config.ts server: { port: 5174 } // increment per project ``` ## Step 9: Testing Foundation ```php // tests/Pest.php uses(Tests\TestCase::class, Illuminate\Foundation\Testing\RefreshDatabase::class)->in('Feature'); ``` Write Pest tests for: auth flows, admin panel access, billing pages, legal pages, all CRUD. ## Step 10: SEO Basics - Add `robots.txt` route - Add dynamic `sitemap.xml` route - Add Open Graph meta tags to public pages ## Verification ```bash php artisan route:list php artisan test npm run build php artisan pint --test ```