Wayfinder is the reusable core framework package behind Stackmint.
It provides the runtime pieces that Stackmint builds on: routing, HTTP, minimal DI, configuration, views, sessions, database access, console tooling, modules, and testing support.
Wayfinder is designed around:
- explicit wiring
- low magic
- model-first application code
- AI-readable structure
- a small dependency surface
It intentionally does not include:
- an ORM
- a large hidden abstraction layer
- an application skeleton or
newproject generator
Wayfinder includes a native queue layer that can be wired explicitly for sync, database, Redis, and Beanstalkd queues. The optional Laravel-backed queue integration remains available under Wayfinder\Integration\LaravelQueue for applications that already use it.
Model= entity behaviorQuery= complex read shapeService= workflowDB= low-level controlDTO= explicit output shape
In PHP views, prefer Wayfinder helpers over raw escaping or hard-coded internal paths:
<?= e($title) ?>
<?= e(url('health')) ?>
<?= e(asset('img/photo.jpg')) ?>See docs/view-helpers.md for the full helper list.
Use path helpers after bootstrap instead of manual __DIR__ path assembly:
storage_path('logs/app.log')
database_path('migrations')
config_path('app.php')See docs/path-helpers.md.
Request::validate() supports common production form and API rules, including presence rules, string and format checks, numeric/date comparisons, nested wildcard array validation, database exists/unique checks, and upload metadata checks.
See docs/validation.md.
Wayfinder's request and response API is backed by Symfony HttpFoundation while keeping the framework's existing controller and middleware surface. Use Wayfinder\Http\Request and Wayfinder\Http\Response in application code; lower-level integrations can access toSymfonyRequest() and toSymfonyResponse() when needed.
See docs/http.md.
Wayfinder includes opt-in hardening primitives for trusted proxies, host validation, secure browser headers, safe redirects, CSRF protection, and strict cookie metadata.
See docs/security.md.
Debug browser requests render a native Wayfinder exception page with source context and stack frames. Production responses stay generic, and debug JSON requests still return structured JSON.
See docs/errors.md.
Wayfinder uses Carbon for date/time handling. Prefer Wayfinder\Support\Date, which returns immutable Carbon dates and supports test clocks through Wayfinder\Support\Clock.
See docs/dates.md.
Wayfinder uses Flysystem for application storage through Wayfinder\Filesystem\Storage. Start with local and public disks, then add remote adapters only when an application needs them.
See docs/filesystems.md.
Wayfinder uses Monolog through the existing Wayfinder\Logging\Logger contract and can also expose Psr\Log\LoggerInterface from the container.
See docs/logging.md.
Wayfinder includes health and readiness primitives for deploy checks across app config, database, cache, storage, and queues. Register the health command lazily so lightweight console commands do not open production connections during bootstrap.
See docs/health.md.
Use php wayfinder migrate --pretend to preview the SQL generated by pending migrations without executing the migrations or writing to the migration log.
When APP_ENV=production, php wayfinder migrate prints pending migrations and asks for confirmation before running. Deployment scripts can use php wayfinder migrate --force to run non-interactively.
Database connections support PDO timeout, persistent connection, and custom option settings. Query listeners can record all SQL timing, while slow-query listeners can alert on queries over a chosen threshold.
See docs/database.md.
Console commands can be registered lazily with Application::addLazy(). Use lazy registration for commands that need database connections, queues, external clients, or other heavy services so lightweight commands like route:list and config:clear do not resolve those services during bootstrap.
Native queues live under Wayfinder\Queue and support sync, database, redis, and beanstalkd drivers. Applications can bind a queue resolver and then dispatch through queue() or Wayfinder\Queue\Queue.
$manager = new Wayfinder\Queue\QueueManager($config, databases: ['default' => db()]);
Wayfinder\Queue\Queue::setResolver(fn (?string $connection = null) => $manager->bus($connection));
queue()->dispatch(new SendWelcomeEmail($userId));Use make:queue-table for the jobs table, make:failed-jobs-table for failed jobs, and queue:work --connection=database --queue=default to process native queued jobs. Workers reserve jobs through the shared queue driver contract, support named queues, release failed jobs until retry attempts are exceeded, and respond to SIGTERM/SIGINT for graceful shutdown. Use --max-jobs=100, --max-time=3600, --memory=128, and --timeout=60 when a process manager should recycle or stop workers predictably.
Redis queue atomic operations are stored as small Lua scripts in src/Queue/Drivers/Redis/Lua.
See docs/queue-workers.md for Supervisor examples covering local sync, production database, production redis, named queues, and worker recycling options.
Wayfinder includes framework-level scenario primitives and scoped fake transport adapters for mail, SMS, queues, and webhooks. Fake transports are ordinary drivers that record delivery intent during tests or scenario runs; application code continues to depend on transport interfaces.
See docs/scenarios.md.
Most developers should start from the Stackmint skeleton rather than consuming the core package in isolation. Wayfinder Core does not ship an app scaffold; Stackmint owns the application layout, default configuration, starter views, and project CLI.
- Stackmint skeleton: https://github.com/Startermint/stackmint
- Full docs: https://github.com/Startermint/stackmint-docs
- Composer package:
wayfinder/core - Namespace root:
Wayfinder\\