Quality and testing

The template ships a small, real quality bar: Pest for PHP, Vitest for the Vite/Echo surface, Pint for format, PHPStan level 5 for analysis, and composer audit for advisories. Security and permission tests are first-class — a module that cannot show guest, wrong-role, wrong-owner, and happy-path is not done (ADR 0002).

Testing doctrine

Security and permission matrices sit beside every first-class system: media, realtime, and any future module. They are not a polish pass after the UI works.

  • Pest covers tests/Unit, tests/Feature, tests/Feature/Api, tests/Feature/Security.
  • Each matrix asserts four cases: guest (unauthenticated), wrong-role (authenticated, missing permission), wrong-owner (authenticated, IDOR), happy-path.
  • Reusable helpers (actingAsRole, actingAsPassport, assertForbiddenTo, assertCannotAccessOthersRecord) live in the template so a later resource copies the matrix instead of inventing rules.
  • Pest uses sqlite :memory: (pinned in TestCase) and Storage::fake() for S3/media. Compose MinIO and libSQL are for humans, not CI. Channel auth for Reverb is HTTP (Broadcast::auth); websocket frames are out of scope.
  • Vitest covers resources/js — the Echo client and any Vite surface. No leaked cloud keys.

Stay on Pest 4 while php is ^8.3. Pest 5 and the arch plugin v5 require PHP ^8.4.

Pest arch()

Architecture-rule tests (arch()->expect(), presets) are in scope as guidelines, not locked rules. Recommended baseline: php() + security() + no-debug. Do not enable laravel() or strict() wholesale — they encode a hexagonal style this template never chose. Enforcement lands once tooling/04 then 05 close; not in the first harness.

Larastan / PHPStan

Level 5, paths: [app/] only. No Psalm. Bumping to level 6 is a human call — Filament core runs at 6 and ignores missingType.generics; the template does not inherit that automatically.

laravel/pao

Agent-only JSON/ANSI wrapper around Pest, PHPStan, and Artisan. Skeleton require-dev. It is not a linter and not Boost — keep it.

composer audit

Packagist advisory check, should-have in CI with --locked. Preferred over roave/security-advisories as the template default.

Quality CI

GitHub Actions live at template/.github/workflows/, working-directory: app, on host PHP + sqlite — not Docker, FrankenPHP, or libSQL. Jobs: Pest, pint --test, PHPStan, npm test, npm run build, composer audit. CI is the gate.

Frontend lint

Biome is the pick if a frontend tool ships — one JS lint+format binary. Laravel 13 and the Livewire kit ship none, so the template does not install it. Echo stays as .js.

Pre-commit

Husky / lint-staged is optional for staged Pint + JS. The git root is template/ and package.json is app/, so the recipe is nested. Researchers split: ship it, or skip it — CI is the gate either way.

Local commands

docker compose exec app artisan test
docker compose exec app vendor/bin/pint --test
docker compose exec app vendor/bin/phpstan analyse
docker compose exec app composer audit --locked
docker compose exec app npm test

See also

Built by Qcentic