Laravel Start is an application template for Codebar Solutions AG Laravel projects (PHP 8.5, Laravel 13). It is a starting point for new applications and includes common packages, security defaults, and tooling.
Runtime (composer.json require):
- Laravel Framework 13.x
- Laravel Nova
- Laravel Nightwatch (production telemetry;
NIGHTWATCH_*, supervisedphp artisan nightwatch:agent,LOG_STACKincludingnightwatch) - Laravel Tinker
- codebar-ag/laravel-microsoft-entra-sso (Microsoft Entra ID / Azure AD SSO)
- codebar-ag/laravel-flysystem-cloudinary and codebar-ag/laravel-flysystem-cloudinary-nova
- league/flysystem-aws-s3-v3 (S3-compatible storage, Lasso bundles)
- Sammyjo Lasso (asset bundles via
config/lasso.phpon thes3disk; production publish in GitHub Actions—see Production assets (Lasso)) - Spatie Laravel Activity Log
- Spatie Laravel CSP (preset
App\Security\SecurityPolicyBasic; allowlists inconfig/csp-allowlists.json, wiring inconfig/csp.php) - Spatie Laravel Flash (flash messages in layouts)
- Spatie Laravel Health plus Spatie Security Advisories Health Check
- Spatie Laravel Honeypot (spam protection on auth POST routes)
- Spatie Laravel Permission
- Spatie Laravel Sitemap (
php artisan sitemap:generate) - Symfony HTTP Client and Symfony Postmark Mailer
Frontend: Blade views, Vite 7, Tailwind CSS 4, Alpine.js 3 (see package.json). This template does not ship Inertia, Fortify, or Livewire in Composer.
Development tooling:
- codebar-ag/coding-guidelines and Laravel Boost (see AI-assisted development)
- Pest 4, Laravel Dusk 8, Larastan / PHPStan, Laravel Pint, Laravel Sail
routes/web.php— authenticated dashboard (start.index); includesroutes/auth.phpapp/Http/Controllers/Auth/— session login, password reset, email verificationapp/Nova/— Nova resources, policies, dashboardsapp/Security/—SecurityPolicyBasic(CSP),FeaturePolicyBasic(Permissions-Policy; usescodebar-ag/laravel-feature-policy)- Permissions-Policy middleware and builder ship in the
codebar-ag/laravel-feature-policyComposer package app/Listeners/Auth/— SSO provisioning, Microsoft profile sync, login/logout hooksapp/Console/Commands/— sitemap, admin grants, Entra migration helpersconfig/microsoft-entra-sso.php— Entra ID OAuth settingstests/Feature,tests/Unit,tests/Browser— Pest feature/unit tests and Dusk browser tests
You can start from this repository with Use this template on GitHub, or clone it directly.
composer install
cp .env.example .env
php artisan key:generate
php artisan boost:install
php artisan boost:update
php artisan migrate --seedThis project expects Node 24 or newer (see package.json engines).
npm install
npm run buildIf you want to use Valet to serve your application, you can run the following command:
valet link
valet secure
valet openIf you want to use Herd to serve your application, you can run the following command:
herd link
herd secure
herd openYou can run the development asset server with the following command:
npm run devNote: You should set
valetTls: 'your-domain.test',belowrefresh: true,in yourvite.config.jsfile if you usevalet secureorherd secure.
Reverse proxies:
bootstrap/app.phpconfigures trusted proxies fromTRUSTED_PROXIES(default*), soX-Forwarded-*matches TLS-terminated local URLs. In production, setTRUSTED_PROXIESto your load balancer or ingress IPs/CIDRs (comma-separated); see Laravel’s trusted proxies documentation.
The template includes codebar-ag/coding-guidelines as a dev dependency (wired via the path repository packages/coding-guidelines, which tracks codebar-ag/coding-guidelines with Laravel 13–compatible illuminate/* constraints). That package ships RULES.md and Boost skills under resources/boost/skills/. See the root AGENTS.md for paths, agent roles (ArchitectAgent, ReviewAgent, etc.), and how to point Claude or other assistants at the canonical rules.
Repository note: Generated Boost and editor assets are not committed—.claude/, .cursor/, .junie/, root .mcp.json, and CLAUDE.md are listed in .gitignore. Canonical skill sources live under vendor/codebar-ag/coding-guidelines/resources/boost/skills/ (and optional project overrides under .ai/skills/). After every clone you must run Boost below so Cursor, Claude Code, Junie, and MCP get local copies of skills and config.
After composer install, set up and refresh Boost (Laravel only registers Boost when the app is not in the PHPUnit/testing bootstrap and the environment is local or APP_DEBUG is true, so use a normal local .env from .env.example, or prefix commands as shown):
php artisan boost:install
php artisan boost:updateWhen your .env uses APP_ENV=testing (for example in some automated setups), run:
APP_ENV=local php artisan boost:install
APP_ENV=local php artisan boost:updateExample prompt (ReviewAgent): “Act as ReviewAgent. Using RULES.md and all skills under resources/boost/skills/**/SKILL.md from codebar-ag/coding-guidelines, review this diff and produce: (1) a short assessment, (2) a file-grouped refactor plan, (3) a few copy-pasteable suggestions.”
Optional CI and MCP setup are described in the coding-guidelines README.
Assets should be set in the following directories:
resources/jsfor JavaScript files.resources/cssfor CSS files.resources/fontsfor Font files.resources/imagesfor Image files.
After you have added your assets, you can run the following command to compile them:
npm run buildTo include your assets in your blade files, you can use the following:
{{ Vite::asset('resources/images/your-image.png') }}Session authentication is enabled by default. Guards and providers live in config/auth.php. HTTP routes are defined in routes/auth.php (prefix auth, named routes auth.*) and implemented by controllers under app/Http/Controllers/Auth/. Sensitive POST routes use throttling and Spatie Honeypot (ProtectAgainstSpam).
After login, users with the user role land on the dashboard (/, route name start.index). The Nova admin link is shown only when Gate::allows('viewNova') (administrators by default). Microsoft SSO creates or links a User, assigns the user role, stores OAuth tokens on microsoft_sso_identities (encrypted at rest via the Entra SSO package), and marks the email verified for that IdP login.
If you wish to use email verification, you can use the following middleware to protect your routes:
Route::middleware(['laravel-auth-middleware'])->group(function () {
...
});The laravel-auth-middleware group is registered in bootstrap/app.php and includes EnsureEmailIsVerified with a redirect to auth.verification.notice.
This template already adds laravel-auth-middleware to Nova in config/nova.php so verified email is required for the admin panel. If you remove it, restore it like this:
'middleware' => [
'web',
'laravel-auth-middleware',
\Laravel\Nova\Http\Middleware\HandleInertiaRequests::class,
'nova:serving',
],SSO is provided by codebar-ag/laravel-microsoft-entra-sso. Configure config/microsoft-entra-sso.php via environment variables (see .env.example):
MICROSOFT_ENTRA_SSO_TENANT_IDMICROSOFT_ENTRA_SSO_CLIENT_IDMICROSOFT_ENTRA_SSO_CLIENT_SECRETMICROSOFT_ENTRA_SSO_REDIRECT_URI(default in.env.example:${APP_URL}/sso/microsoft/web/callback)
For local development, APP_URL must be reachable by Microsoft (use expose or ngrok) and the redirect URI in Entra must match exactly.
APP_URL=https://your-expose-or-ngrok-url.example
MICROSOFT_ENTRA_SSO_REDIRECT_URI="${APP_URL}/sso/microsoft/web/callback"Please refer to the Spatie Permission documentation for more information on how to use permissions.
Enums are included in PHP's core functionality but we have some additional functionality to make them easier to use.
You can create an enum in the app/Enums directory:
<?php
namespace App\Enums;
use App\Traits\HasNovaEnumLabelTrait;
enum EnvironmentEnum: string
{
use HasNovaEnumLabelTrait;
case PRODUCTION = 'production';
case STAGING = 'staging';
case LOCAL = 'local';
public function getLabel(): string
{
return match ($this) {
EnvironmentEnum::PRODUCTION => __('Production'),
EnvironmentEnum::STAGING => __('Staging'),
EnvironmentEnum::LOCAL => __('Local'),
};
}
}You should use the HasNovaEnumLabelTrait trait to add label functionality to your enum.
The trait provides both getLabel() and label() methods, with label() being an alias for Nova integration.
The label method should return the label for the enum value.
You can use the enum in your code like this:
// Native PHP Enum
$enum = EnvironmentEnum::PRODUCTION; // Enum Object
$name = EnvironmentEnum::PRODUCTION->name; // Enum Name (PRODUCTION)
$value = EnvironmentEnum::PRODUCTION->value; // Enum Value (production)
// Label
$label = EnvironmentEnum::PRODUCTION->label(); // Enum Label using Laravels Translation (Production)
// Labels
$labels = EnvironmentEnum::labels(); // Array of Enum Labels with Enum value as Key (['production' => 'Production', 'staging' => 'Staging', 'local' => 'Local'])This app runs spatie/laravel-health checks on a schedule (RunHealthChecksCommand every five minutes). Individual checks may still define their own intervals (for example everyFiveMinutes() in AppServiceProvider). In production, add a cron entry:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1Alerts use Oh Dear: enable OH_DEAR_HEALTH_CHECK_ENABLED, set OH_DEAR_HEALTH_CHECK_SECRET to match Oh Dear, and configure the monitor URL as APP_URL + OH_DEAR_HEALTH_CHECK_PATH (default /oh-dear-health-check-results). Oh Dear sends the oh-dear-health-check-secret header automatically.
Please refer to the Spatie Health documentation for more information on how to use health checks.
Registered checks in AppServiceProvider include Spatie’s DebugModeCheck, CacheCheck, OptimizedAppCheck, EnvironmentCheck (production only), SecurityAdvisoriesCheck (spatie/security-advisories-health-check, last day of month), and custom checks in app/Checks:
JobsCheckFailedJobsCheck
We have added some helper functions which are located in the app/Helpers directory.
You should use the Facades for the helpers which are located in the app/Helpers/Facades directory:
HelperBankHelperDateHelperDeviceHelperFileHelperMarkdownHelperMoneyHelperNumberHelperPhone
Laravel Nightwatch is part of this template’s production story. Set NIGHTWATCH_TOKEN from your Nightwatch dashboard, run the ingest agent (php artisan nightwatch:agent) under process supervision wherever the app runs, and keep LOG_STACK including nightwatch (see .env.example). Use NIGHTWATCH_ENABLED=false only when the agent is intentionally not running (for example some local setups). Configuration defaults load from the package; run php artisan vendor:publish --tag=nightwatch-config when you need a project-local config/nightwatch.php.
Content-Security-Policy is applied by Spatie Laravel CSP. The active preset is App\Security\SecurityPolicyBasic, configured in config/csp.php. Third-party source lists are merged from config/csp-allowlists.json via App\Support\CspAllowlist. Toggle with CSP_ENABLED (see .env.example). Middleware is registered in bootstrap/app.php (AddCspHeaders).
Permissions-Policy (legacy filename config/feature-policy.php) is implemented by codebar-ag/laravel-feature-policy (AddFeaturePolicyHeaders and related types). The app policy class is App\Security\FeaturePolicyBasic. Toggle and reporting options live in config/feature-policy.php. This is separate from CSP. Middleware is registered in bootstrap/app.php.
Custom Blade error pages live under resources/views/errors/ (shared partials under errors/partials/). Copy is driven by translation files such as lang/en_CH/errors.php (and other *_CH locales). Feature coverage includes tests/Feature/HttpErrorPagesTest.php (assertions use APP_DEBUG=false).
We have added some traits which are located in the app/Traits directory.
HasUuidTraitHasActivityTraitHasNovaEnumLabelTrait
We also have some traits which are located in the app/Nova/Traits directory which are intended for use only in Laravel
Nova.
NovaCustomOrderTraitNovaIdentificationPanelTraitNovaLanguageTraitNovaTimestampsPanelTrait
Reusable UI primitives are Blade components under resources/views/components/ui/ (for example x-ui.button, x-ui.input, x-ui.callout).
Analytics and SEO partials are included from layouts, for example:
resources/views/layouts/_partials/analytics/_fathom.blade.phpresources/views/layouts/_partials/analytics/_userback.blade.phpresources/views/layouts/_partials/seo/_favicons.blade.php
Wire flash messages and SSO error UI via resources/views/layouts/_partials/_flash.blade.php (Spatie Flash flash()->message / session keys).
Please refer to the respective documentation for the Cloudinary and Cloudinary Nova packages.
Transactional mail uses standard Laravel notifications under app/Notifications/ (for example password reset and email verification). For in-page feedback, use Spatie Laravel Flash together with _flash.blade.php and the x-ui components.
We use Laravel Pint to format code.
You can run the following command to format your code:
./vendor/bin/pintYou can run the following command to format your blade files:
./vendor/bin/pint --bladeThe blade formatter is still in beta and may not work as expected. if you wish to not use this update your
composer.jsonto use the latest version oflaravel/pintinstead of the dev branch.
After deploy (and when not actively debugging config), cache framework metadata:
php artisan optimize
# or, when you need finer control:
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cacheFor higher traffic, prefer Redis for SESSION_DRIVER and CACHE_STORE (see config/database.php, config/session.php, config/cache.php). Use QUEUE_CONNECTION=database or redis with a real worker process for anything slow (mail, imports, etc.); consider Laravel Horizon when you standardize on Redis queues.
Run PHP with OPcache enabled in production. For local builds use npm run build. For hosted bundles, run php artisan lasso:pull during deploy (before config/route/view cache) so public/ matches the published bundle; see Production assets (Lasso).
Review indexes on users.email, microsoft_sso_identities, activity log, and Spatie permission tables as your data grows.
microsoft_sso_identities.token and refresh_token are stored with Laravel’s encrypted cast (see the Entra SSO package). If you rotate APP_KEY, existing ciphertext cannot be decrypted—expect users to sign in with Microsoft again.
CI needs Composer authentication for Nova (NOVA_USERNAME / NOVA_LICENSE_KEY or COMPOSER_AUTH). Workflows in .github/workflows/ also configure the Flux Composer registry (FLUXUI_USERNAME / FLUXUI_LICENSE_KEY) for consistency with Codebar pipelines; add any other secrets your jobs need (Nightwatch, OAuth test doubles, etc.). Do not commit real .env values; use repository secrets and short-lived tokens.
On every push to production, .github/workflows/lasso_publish_production.yml runs npm ci, compiles with Vite inside php artisan lasso:publish (with --no-git and --with-commit from the Git commit SHA), uploads the bundle to object storage, then—if you set the secret below—POSTs to your Laravel Cloud deploy hook with commit_hash set to that SHA. A non-success HTTP response from the hook fails the workflow (unlike Lasso’s optional in-app webhook, which swallows HTTP errors). Configure per-repository secrets (Settings → Secrets and variables → Actions):
| Secret | Purpose |
|---|---|
AWS_ACCESS_KEY_ID |
S3-compatible access key |
AWS_SECRET_ACCESS_KEY |
S3-compatible secret |
AWS_DEFAULT_REGION |
Region (e.g. fra1 for DigitalOcean Spaces) |
AWS_BUCKET |
Bucket name |
AWS_ENDPOINT |
Optional; required for many S3-compatible providers (e.g. Spaces). Omit for default AWS endpoints. |
LARAVEL_CLOUD_DEPLOY_WEBHOOK_URL |
Optional; your Laravel Cloud deploy hook URL. The workflow calls it only after lasso:publish succeeds (see Laravel Cloud deploy hooks). Omit the secret to skip deploy from this job. |
Use the same variables in your deployed app’s environment so lasso:pull reads from the same bucket/prefix. On Laravel Cloud, disable deploy on every commit if you rely on this hook so deploys start only after assets are uploaded.
config/lasso.php can still list LARAVEL_CLOUD_DEPLOY_WEBHOOK_URL under webhooks.publish for local lasso:publish runs with a real .env; GitHub Actions does not put that variable in the CI .env, so CI uses only the explicit workflow step and does not double-trigger the hook.
On Laravel Cloud, set the same S3-compatible values as in production .env (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, AWS_BUCKET, and AWS_ENDPOINT if your provider needs it). Set LASSO_ENV to the same value used when GitHub runs lasso:publish (e.g. production). The s3 disk uses a fixed bucket root (/ in config/filesystems.php); Lasso stores under lasso/{LASSO_ENV}/ there.
In the environment’s deploy script (build/deploy commands Laravel Cloud runs for each deployment), pull compiled assets after dependencies and migrations are in place, and before you cache config/routes/views so public/ already contains the bundle Vite emitted. For example:
php artisan migrate --force
php artisan lasso:pull --no-interaction
php artisan optimizeIf you prefer explicit cache steps instead of optimize, run lasso:pull before php artisan config:cache, route:cache, view:cache, and event:cache. Do not rely on npm run build on Laravel Cloud if this template’s GitHub workflow already publishes bundles; otherwise you may overwrite or race the Lasso bundle.
If you set LARAVEL_CLOUD_DEPLOY_WEBHOOK_URL in Actions, turn off automatic deploy on every Git push in Laravel Cloud so each deploy runs only after this workflow finishes lasso:publish and successfully POSTs the deploy hook.
We use Pest 4 on Laravel 13. PHPUnit/Pest use DB_DATABASE=laravel_test (see phpunit.xml and .env.testing); create that database on your Postgres instance before running tests (for example createdb laravel_test).
Match pull-request CI (PHPStan + Pest without tests/Browser):
composer verifyThat runs composer analyse (Larastan / PHPStan) and composer test (same paths as .github/workflows/pest_pull_request.yml).
Pest type coverage (also used in CI; does not require Xdebug):
composer test:type-coveragePest code coverage with the --min=90 gate needs PCOV or Xdebug enabled for PHP. Without a driver, Pest exits with “No code coverage driver is available.” CI enables Xdebug for that job. Locally:
composer test:coverageRun the full default suite (includes tests/Browser; those tests skip unless RUN_BROWSER_TESTS=1 / Dusk is set up):
composer test:all
# or: php artisan test --compactRun a subset with a path or filter:
php artisan test --compact tests/Feature/HttpErrorPagesTest.php
php artisan test --compact --filter=someTestNameYou can also invoke Pest directly:
./vendor/bin/pestBrowser tests (Dusk): copy .env.dusk.example to .env.dusk.local and align APP_URL with your local HTTPS domain (see the comment in .env.example). Then:
composer dusk
# or: php artisan duskStatic analysis uses Larastan / PHPStan (./vendor/bin/phpstan analyse or composer analyse). The type_coverage thresholds in phpstan.neon.dist are set to a low baseline (10 on param/return/property/constant, 0 on declare) so CI stays green; raise them as you add types.
Please refer to the PestPHP documentation for more information on how to use PestPHP.
The Laravel framework is open-sourced software licensed under the MIT license.