Development
Day-to-day development on Reshape means running two apps at once: the Laravel API and the Vue frontend. Both have a single command that brings up everything they need.
Running the apps
API
cd api
composer devcomposer dev uses concurrently to run four processes in one terminal, each with its own color and prefix:
| Process | Command | What it does |
|---|---|---|
server | php artisan serve | The HTTP server on port 8000 |
queue | php artisan queue:listen --tries=1 | Processes queued jobs (notifications, broadcasts, Stripe syncs) |
logs | php artisan pail --timeout=0 | Live-tails the application log in your terminal |
vite | npm run dev | Assets for the Filament admin panel |
If any process dies, the whole group stops (--kill-others), so you never end up with a half-running stack.
Frontend
cd web
npm run devThis starts the TanStack Start dev server on port 3000 with hot module replacement. With the Caddy proxy from Installation running, the app is available at https://reshape.test.
Reverb (websockets)
Real-time features — notifications delivered to the in-app panel — need the Reverb server:
cd api
php artisan reverb:start --host=0.0.0.0 --port=9000The Caddyfile from the installation guide proxies wss://api.reshape.test/app/... to this process, so the frontend connects over TLS without extra configuration.
TIP
You only need Reverb running when you're working on real-time features. Everything else works without it — the frontend simply won't receive live pushes.
Logging in locally
Login is passwordless: you enter your email, receive a one-time code, and type it in. Locally there are two convenient ways to handle this:
Read the code from the log. With the default MAIL_MAILER=log, the email containing the code is written to storage/logs/laravel.log — and since composer dev runs Pail, it scrolls past right in your terminal.
Skip login entirely. Set the auto-login variable in api/.env:
AUTO_LOGIN_USER_EMAIL=user@reshape.testIn the local environment, every request is automatically authenticated as that user (see AppServiceProvider). This is the fastest way to work on authenticated screens — just remember it applies to every request, so unset it when you're working on the login flow itself.

Testing
The API is tested with Pest 4. Tests run against an in-memory SQLite database with sync queues, so they're fast and isolated:
cd api
composer test:unit # pest --parallel
php artisan test --compact # alternative runner
php artisan test --compact --filter=CompanyMemberTestRequest payloads in tests are built with worksome/request-factories — see tests/RequestFactories/ for the existing factories.
The full quality gate runs the test suite, the linters in check mode, and static analysis:
composer test # test:unit + test:lint + test:typesCode style & static analysis
PHP
composer lint # Rector, then Pint — fixes everything it can
composer test:lint # check-only versions of both
composer test:types # PHPStan (Larastan) at level 9Formatting is Pint (config in pint.json), automated refactoring is Rector (config in rector.php), and static analysis is Larastan at level 9 — the strictest level, so new code is expected to be fully typed.
To keep your IDE and PHPStan happy about Eloquent models, regenerate the helper files after changing models:
composer types:generate # ide-helper:generate + eloquent + models --write-mixinFrontend
The web/ app uses oxlint and vue-tsc:
cd web
npm run lint # oxlint --vue-plugin --import-plugin .
npm run lint:fix
npm run typecheck # vue-tsc --noEmit
npm run build # production build + typecheckQueues and jobs
Locally, the queue uses the database driver and composer dev already runs a listener. Two things worth knowing:
- Notifications and broadcasts are queued — if the notification panel seems dead, check that the queue process is running.
- Queues are tenant-aware (via Spatie Multitenancy): jobs dispatched while a company is current run in that company's context. See Companies for what "current" means.
The admin panel
Reshape also ships a Filament admin panel — see Filament for where it lives.