esfredderick / rilt-psql-blank-starter-kit
The skeleton application for the Laravel framework.
Package info
github.com/esfredderickmx/rilt-psql-blank-starter-kit
Type:project
pkg:composer/esfredderick/rilt-psql-blank-starter-kit
Requires
- php: ^8.2
- inertiajs/inertia-laravel: ^3.0
- laravel-lang/common: ^6.7
- laravel/framework: ^13.0
- laravel/tinker: ^3.0
- laravel/wayfinder: dev-next
Requires (Dev)
- esfredderick/useful-artisan-commands: ^1.0
- fakerphp/faker: ^1.23
- larastan/larastan: ^3.0
- laravel/boost: ^2.0
- laravel/pail: ^1.2.2
- laravel/pint: ^1.24
- laravel/sail: ^1.41
- mockery/mockery: ^1.6
- nunomaduro/collision: ^8.6
- pestphp/pest: ^4.4
- pestphp/pest-plugin-laravel: ^4.0
README
An opinionated Laravel starter kit built on PostgreSQL schemas, Inertia v3 + React 19, and an action-based architecture. Designed for developers who want clear domain boundaries, type safety across the full stack, and sensible defaults from day one.
Stack
| Layer | Technology |
|---|---|
| Backend | Laravel 13, PHP 8.4 |
| Frontend | React 19, TypeScript, Inertia v3 |
| Database | PostgreSQL (named schemas) |
| Styling | Tailwind CSS v4, shadcn/ui |
| Type Bridge | Laravel Wayfinder (dev-next) |
| Testing | Pest 4 |
| Static Analysis | Larastan (PHPStan), ESLint, Prettier |
| Code Style | Laravel Pint |
Getting Started
Requires PHP 8.2+, PostgreSQL, Node.js, and pnpm.
Create your app using Laravel installer:
laravel new my-app --using=esfredderick/rilt-psql-blank-starter-kit
Initial setup
cd example-app # runs migrations using your own db credentials composer setup # runs the dev server composer dev
Architecture Overview
Important
This section describes the conventions and patterns embedded in this starter kit — not automatic behaviors. They define how the codebase is structured and how new features should be built. Detailed guidelines live in .ai/guidelines/project-architecture.md.
PostgreSQL Schemas as Domain Boundaries
Tables live in named schemas instead of the default public schema. Treat each schema as a domain boundary and keep schema, table, and folder examples placeholder-based so each application can choose its own domain names. Schemas are created via dedicated migrations, and models declare their table with schema-qualified names:
protected $table = '{domain}.{table}';
The esfredderick/useful-artisan-commands package automatically creates the database and migration schema when they don't exist during migration commands - no application service provider setup required while Laravel package discovery is enabled. When Laravel framework table defaults need to move into named schemas, run php artisan schemas:config-defaults from the same package to schema-qualify the relevant configuration defaults.
Domain-Driven Directory Structure
Database schemas and table concerns mirror into PHP namespaces and frontend directories. Models stay directly under the domain namespace, and route files are grouped by domain:
app/
Actions/{Domain}/{Subdomain}/
Data/{Domain}/{Subdomain}/
Exceptions/{Domain}/{Subdomain}/
Http/Controllers/{Domain}/{Subdomain}/
Http/Requests/{Domain}/{Subdomain}/
Models/{Domain}/
resources/js/
components/domain/{domain}/{subdomain}/
pages/{domain}/{subdomain}/
routes/
domain/{domain}.php
tests/
Feature/{Domain}/
Action-Based Business Logic
All business logic goes into Action classes — controllers stay thin. Artisan commands for generating both are provided by esfredderick/useful-artisan-commands:
php artisan make:action {Domain}/{Subdomain}/{ActionName} # -> app/Actions/{Domain}/{Subdomain}/{ActionName}Action.php (-d to also create DTO)
php artisan make:data {Domain}/{Subdomain}/{DataName} # -> app/Data/{Domain}/{Subdomain}/{DataName}Data.php
Actions are plain classes with a handle() method. DTOs are final readonly classes used when actions need three or more input values.
Thin Controllers
Controllers follow a strict injection order and flow:
FormRequest → Route params → Action (via method DI)
Form Requests handle validation and expose a getData() method that transforms input into a DTO. The controller calls $action->handle($request->getData()), flashes feedback via Inertia::notify(), and redirects.
Exception Handling
AppException is the base exception class. Domain-specific exceptions extend it and auto-render as flash messages — no try-catch needed:
throw new InsufficientBalanceException(); // flashes + redirects back automatically
Frontend Feedback System
Two flash channels from backend to frontend:
- Callout — persistent inline alert via
<ResponseCallout /> - Transient — auto-dismissing Sonner toast via
useTransientListener()
Both are triggered through a single macro:
Inertia::notify('Done!', ResponseStyle::TRANSIENT); Inertia::notify('Check this.', ResponseStyle::CALLOUT, EmphasisVariant::INFORMATIVE);
Emphasis Variant System
A semantic color/icon system spanning the full stack:
- Backend:
EmphasisVariantenum (AFFIRMATIVE,INFORMATIVE,PREVENTIVE,DESTRUCTIVE,INTERROGATIVE,NEUTRAL) - Type Bridge: Wayfinder auto-generates TypeScript constants and types
- CSS: Custom
oklch()color tokens per variant (light + dark) - Components: shadcn
Alertextended with variant classes,useDecorator()hook for icon resolution
Wayfinder Type Bridge
Laravel Wayfinder (dev-next) generates typed TypeScript from Laravel routes, models, enums, form requests, and Inertia page props. All output lives under resources/js/wayfinder/ and auto-regenerates via Vite plugin during development.
Inertia shared props and flash data are typed through module augmentation in resources/js/types/global.d.ts.
Frontend Conventions
- UI primitives from shadcn/ui live in
components/ui/ - Custom reusable components live in
components/ux/using composition pattern - Decoration records map enum variants to UI properties via
Pick<Decoration, ...>— seedecorations/ui/emphasis-decoration.ts - Theme managed by
useAppearance()hook (light/dark/system, cookie-persisted for SSR)
Custom Available Commands
Commands provided by esfredderick/useful-artisan-commands (dev dependency):
| Command | Description |
|---|---|
php artisan make:action {name} |
Action class (auto-suffixed, -d to also create DTO) |
php artisan make:data {name} |
DTO class (auto-suffixed) |
php artisan app:config-db |
Re-configures PostgreSQL credentials directly in .env |
php artisan schemas:config-defaults |
Schema-qualifies Laravel framework table defaults for PostgreSQL schema/domain setups |
Code Quality
| Command | Description |
|---|---|
composer run quality |
Prettier + ESLint + Pint + Larastan |
All standard php artisan make:* commands (model, controller, request, migration, etc.) are available as usual.
Application Defaults
Configured in AppServiceProvider:
CarbonImmutableas default date class- Strict model mode outside production
- Destructive DB commands prohibited in production
- Aggressive Vite prefetching
- HTTPS forced in production
- Password rules enforced in production (min 12, mixed case, symbols, uncompromised)
License
MIT