fissible / watch
API cockpit UI for Laravel — mounts a live dashboard, route browser, drift detector, spec manager, and version tracker at /watch in any Laravel application
Requires
- php: ^8.2
- fissible/accord: ^1.0
- fissible/drift: ^1.0
- fissible/forge: ^1.0
- illuminate/routing: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- illuminate/view: ^11.0|^12.0
- sebastian/diff: ^6.0 || ^7.0
- symfony/yaml: ^6.0|^7.0
Requires (Dev)
- phpunit/phpunit: ^11.0
README
API cockpit UI for Laravel. Mounts a live dashboard, route browser, drift detector, spec manager, version tracker, and API explorer at /watch in any existing Laravel application.
Depends on: fissible/accord + fissible/drift + fissible/forge (requires all three).
[forge] ──────────────────────────────► [accord] ◄── [watch] ← you are here
generate / update spec validate at bolt-on cockpit UI
▲ runtime │
│ ▼
└────────────────────────────────── [drift]
detect drift, bump version
watch sits on top of the full stack and exposes everything through a browser-based cockpit — no CLI required for day-to-day API work.
What's inside
| Feature | Path | Always shown |
|---|---|---|
| Dashboard | /watch |
✓ |
| Route browser | /watch/routes |
✓ |
| OpenAPI spec viewer | /watch/spec |
✓ |
| Drift detector | /watch/drift |
✓ |
| Forge (spec generation) | /watch/forge |
✓ |
| Version manager | /watch/versions |
✓ |
| Trace (API explorer) | /watch/trace |
when route registered |
| Testing | /watch/testing |
when route registered |
| Faults (exception tracking) | /watch/faults |
when fissible/fault installed |
Trace, Testing, and Faults are modular — their nav links appear only when the corresponding routes exist (Route::has()). A base watch install shows only the core six pages.
Installation
composer require fissible/watch
The service provider registers automatically via Laravel's package discovery.
Publish the routes file so you can add your own auth middleware:
php artisan vendor:publish --tag=watch-routes
This writes routes/watch.php to your application. Add auth middleware to the route group in that file before anything you want protected:
Route::prefix('watch') ->middleware([StampCsrfToken::class, 'auth']) ->group(function () { // cockpit routes... });
Optionally publish the config:
php artisan vendor:publish --tag=watch-config
Configuration
WATCH_WRITABLE=true # enable write actions (spec generation, version bumps, stub generation) WATCH_ENV_THEME=staging # force a UI theme: staging | production WATCH_PREFIX=watch # URL prefix (default: /watch) WATCH_BRAND=watch # nav brand name (override in standalone apps, e.g. WATCH_BRAND=myapp)
WATCH_WRITABLE gates all mutating routes (spec write, drift apply, stub generation, Trace). Leave it false in shared and production environments — the cockpit remains fully read-only.
WATCH_ENV_THEME activates a persistent visual indicator in the nav: amber for staging, red for production. When an env theme is active, the per-user theme switcher is hidden.
WATCH_BRAND changes the brand name shown in the top-left of the nav. Useful when embedding watch in a standalone app under a different product name.
Middleware
watch registers two middleware aliases automatically:
| Alias | Behaviour |
|---|---|
watch.writable |
Aborts 403 when WATCH_WRITABLE is not true |
watch.local |
Aborts 403 outside local, development, and testing environments |
Apply them to your own routes as needed. Trace requires both: it is guarded by ['watch.local', 'watch.writable'].
CSRF and HTMX
watch uses HTMX for all server round-trips. Include StampCsrfToken middleware on the watch route group so the CSRF token stays in sync after session-mutating commands like migrate:fresh:
use Fissible\Watch\Http\Middleware\StampCsrfToken; Route::prefix('watch')->middleware([StampCsrfToken::class])->group(function () { // ... });
The layout JS reads the X-CSRF-TOKEN response header after each HTMX response and refreshes <meta name="csrf-token">. HTMX forms must not use @csrf — the baked _token input would be stale after migrate:fresh. HTMX reads the token from the meta tag via a htmx:configRequest listener instead.
Modular nav
The left nav adapts to what is installed:
- Trace appears when
Route::has('watch.trace')is true - Testing appears when
Route::has('watch.testing')is true - Faults appears when
Route::has('watch.faults')is true (requires fissible/fault)
If none of the "Dev" section items are present, the Dev heading is also hidden.
UI stack
- HTMX — all server round-trips; partial views are returned and swapped into
hx-targetelements - Alpine.js — client-side interactivity (toggles, modals, tree state)
- No build step — both loaded from CDN in the layout; no
npm run buildrequired
Blade component namespace
watch registers its views under the watch namespace and its anonymous components under the watch prefix:
<x-watch::layout title="My Page"> ... </x-watch::layout> <x-watch::version-tabs :versions="$versions" />
Packages that extend the cockpit (like fissible/fault) use <x-watch::layout> to inherit the full nav and theme system.
Extending the cockpit
Any package can add pages to the cockpit by:
- Registering routes under the
watch.*naming convention (e.g.watch.faults,watch.faults.show) - Using
<x-watch::layout title="...">in its Blade views - Relying on
Route::has('watch.yourpage')to make the nav link appear automatically — no changes to watch itself required
See fissible/fault for an example.
Prerequisites
fissible/accord must be configured with a spec source before watch can show drift or validate routes. See the accord README for setup instructions.
Pilot
Pilot is the standalone reference application that ships this cockpit alongside a demo API, a testing page, and a user story framework. Use Pilot if you want everything pre-wired in one place; use watch if you want to bolt the cockpit onto an existing Laravel API.
License
MIT