Production Requirements & Configuration
Production Requirements & Configuration
Because Tokomono Chat (tokomono/chat) processes AI turns asynchronously on a background queue and streams live token deltas over WebSockets, a production deployment requires a few services and settings to be active.
1. What Must Be Running in Production?
To run tokomono/chat in production, make sure the following four components are enabled and configured:
| Component | Why It Is Required | What Needs to Run |
|---|---|---|
1. Queue Worker (chat queue) |
Every user message dispatches Tokomono\Chat\Jobs\ProcessChatTurnJob onto the configured chat queue (config('chat.queue', 'chat')) with a job timeout of 110 seconds. |
A queue worker (or Laravel Horizon supervisor) listening to the chat queue with --timeout=120. |
| 2. WebSocket Server (Laravel Reverb) | Token deltas, tool calls, and completion events are broadcast immediately via ChatStreamEvent (ShouldBroadcastNow) over private-tokomono-chat.{conversationId}. |
Laravel Reverb (php artisan reverb:start) or a managed Reverb WebSocket cluster, reachable over HTTPS/WSS (port 443). |
| 3. Persistent File Storage | User-uploaded attachments (images, PDFs, CSVs) are stored on the disk configured in config('chat.attachments.disk', 'public'). |
Either a linked local public disk (php artisan storage:link) on single-server setups, or an S3/Cloudflare R2 disk on multi-server/cloud setups. |
| 4. Frontend Echo & Vite Assets | <TokomonoChat /> and <TokomonoChatWidget /> use window.Echo to subscribe to private channels and display the live Online / Offline indicator. |
window.Echo initialized with broadcaster: 'reverb' and frontend assets compiled via npm run build with the VITE_REVERB_* variables present. |
2. Production Environment Variables (.env)
Ensure the following environment variables are configured in your production .env:
# 1. Broadcasting & Laravel Reverb
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=your-reverb-app-id
REVERB_APP_KEY=your-reverb-app-key
REVERB_APP_SECRET=your-reverb-app-secret
REVERB_HOST="chat.yourdomain.com"
REVERB_PORT=443
REVERB_SCHEME=https
# Exposed to Vite during `npm run build` so window.Echo connects to Reverb
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
# 2. Queue & Chat Worker Settings
QUEUE_CONNECTION=redis
CHAT_QUEUE=chat
CHAT_CHANNEL_PREFIX=tokomono-chat
CHAT_SLOW_RESPONSE_THRESHOLD=30
# 3. File Attachments Disk ('public' or 's3' / 'r2')
CHAT_ATTACHMENTS_DISK=public
# 4. Disable Debug Diagnostics in Production
APP_DEBUG=false
CHAT_DEBUG=false
# 5. AI Provider Credentials (used by laravel/ai and tokomono/ai-suite)
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=...
GEMINI_API_KEY=...
Important: Because Vite embeds
VITE_REVERB_*environment variables into the compiled JavaScript bundle at build time, you must always runnpm run buildafter setting or changingREVERB_APP_KEYorREVERB_HOST.
3. Configuring window.Echo in Your Frontend
The Vue components (<TokomonoChat /> and <TokomonoChatWidget />) read window.Echo to monitor WebSocket health and authorize private conversation channels (POST /api/chat/{hash}/broadcasting/auth).
In your resources/js/app.ts or resources/js/bootstrap.js, initialize Laravel Echo and attach it to window.Echo:
import { configureEcho, echo } from '@laravel/echo-vue';
configureEcho({
broadcaster: 'reverb',
});
if (typeof window !== 'undefined') {
window.Echo = echo();
}
Or when using laravel-echo and pusher-js directly:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
4. Configuring Queue Workers & Laravel Horizon
By default, tokomono/chat dispatches ProcessChatTurnJob onto the chat queue (CHAT_QUEUE=chat). Because LLM streaming and multi-step tool/workflow calls can take longer than standard jobs, ProcessChatTurnJob sets $timeout = 110. Your queue worker must listen to the chat queue and use a timeout of at least 120 seconds.
If you use Laravel Horizon, add a dedicated supervisor-chat block in config/horizon.php:
'defaults' => [
'supervisor-chat' => [
'connection' => 'redis',
'queue' => ['chat'],
'balance' => 'auto',
'autoScalingStrategy' => 'time',
'maxProcesses' => 3,
'maxTime' => 0,
'maxJobs' => 0,
'memory' => 128,
'tries' => 1,
'timeout' => 120,
'nice' => 0,
],
],
'environments' => [
'production' => [
'supervisor-chat' => [
'maxProcesses' => 5,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
],
],
5. Securing the Chat Admin UI (config/chat.php)
By default, config/chat.php protects the standalone Chat Admin UI (/chat) with BlockByDefaultMiddleware::class, which denies all requests unless replaced. To enable the Admin UI in production for authorized administrators, replace the middleware in config/chat.php:
'middleware' => ['web', 'auth', 'can:viewChatAdmin'],
6. Verifying Your Deployment with the Built-In Debug Menu (ChatDebugModal)
tokomono/chat includes a built-in Debug Diagnostics Menu (ChatDebugModal.vue) designed specifically to troubleshoot WebSocket, Reverb, and channel authorization issues during development, staging, or initial production verification.
How to Enable or Disable the Debug Menu
- Globally via
.env/config/chat.php:
(WhenCHAT_DEBUG=trueCHAT_DEBUGis omitted,config/chat.phpfalls back toAPP_DEBUG.) - Per Chat Class (
isDebug()): You can also overrideisDebug(): boolon a specific PHPChatclass (for example, to allow only admins to open the debug menu in production):public function isDebug(): bool { return auth()->user()?->isAdmin() ?? false; }
Security Note: When
config('chat.debug')isfalse, the diagnostic API endpoints (GET /api/chat/{hash}/debug/statusandPOST /api/chat/{hash}/debug/ping) automatically return403 Forbidden. Always setCHAT_DEBUG=falsein production once verification is complete.
Opening the Debug Menu
When debug mode is active, an amber debug badge appears in the top-right corner directly above <TokomonoChat /> and <TokomonoChatWidget />. Clicking this badge opens the Tokomono Chat Diagnostics modal and automatically runs a live end-to-end check across three sections:
| Section in Debug Menu | What It Checks | What to Look For |
|---|---|---|
| 1. Reverb Connectie Status | Inspects the client-side window.Echo WebSocket state and queries GET /api/chat/{hash}/debug/status for the server broadcaster configuration. |
- Status badge: Verbonden (green) or Niet verbonden (offline) (red)- Socket ID: Active Pusher/Reverb socket ID (e.g. 123456.789012)- Broadcaster Driver: reverb (host:port) configured on the server |
| 2. Private Kanaal Autorisatie | Verifies subscription to private-tokomono-chat.{conversationId} and tests POST /api/chat/{hash}/broadcasting/auth. |
- Status badge: Verbonden & Geautoriseerd (green), Auth OK (WS Offline) (amber), or Autorisatie Fout (red)- Kanaal: Full private channel name - Deelnemer Modus: authenticated_user or guest_token- Auth Endpoint Check: 200 OK (HMAC geldig) or error message |
| 3. Bericht Sturen & Ontvangen Test | Dispatches a real ChatStreamEvent (debug.pong) via POST /api/chat/{hash}/debug/ping and waits up to 4 seconds for it to arrive over the private WebSocket. Includes an Opnieuw testen button. |
- Verzenden (Server → Reverb): OK if the Laravel backend delivered the event to Reverb's HTTP API, or FOUT if REVERB_HOST/REVERB_PORT is unreachable from PHP.- Ontvangen (Private WS): Displays round-trip latency in ms (e.g. 18 ms) when received, or TIMEOUT if php artisan reverb:start is not running or blocked by your Nginx proxy. |