# Realtime Messaging

Skinbase messaging now uses Laravel Reverb, Laravel Broadcasting, Laravel Echo, Redis-backed queues, and Laravel Horizon for queue visibility.

## v2 capabilities

- Presence is exposed through a global `presence-messaging` channel for inbox-level online state.
- Conversation presence still uses the per-thread presence channel so the header can show who is actively viewing the room.
- Typing indicators remain ephemeral and Redis-backed.
- Read markers are stored on conversation participants and expanded into `message_reads` for durable receipts.
- The conversation list response now includes `summary.unread_total` for global badge consumers.
- Reconnect recovery uses `GET /api/messages/{conversation_id}/delta?after_message_id=...`.
- Delta recovery also returns the latest conversation summary and aggregate unread total so the inbox sidebar can heal after a missed `conversation.updated` broadcast.
- Presence heartbeats use `POST /api/messages/presence/heartbeat` and are intended only to support offline fallback notification logic plus server-side presence awareness.
- Message sends are idempotent per sender and conversation when the client retries with the same `client_temp_id`.
- The database also enforces sender-scoped `client_temp_id` uniqueness so retry races cannot persist duplicate rows.

## Local setup

1. Set the Reverb, Redis, messaging, and Horizon values in `.env`.
2. Run `php artisan migrate`.
3. Run `npm install` if dependencies are not installed.
4. Start the websocket server with `php artisan reverb:start --host=0.0.0.0 --port=8080`.
5. Start queue workers with `php artisan queue:work redis --queue=broadcasts,notifications,default --tries=1`.
6. Start the frontend with `npm run dev` or build assets with `npm run build`.

## Horizon

- Horizon is installed for production queue monitoring and uses dedicated supervisors for `broadcasts` and `notifications` alongside the default queue.
- The scheduler now runs `php artisan horizon:snapshot` every five minutes so the dashboard records queue metrics.
- On Windows development machines, Horizon itself cannot run because PHP lacks `ext-pcntl` and `ext-posix`; that limitation does not affect Linux production deployments.
- Use `php artisan horizon` on Linux-based environments and keep the dashboard behind the `viewHorizon` gate.

## Production notes

- Use `BROADCAST_CONNECTION=reverb` and `QUEUE_CONNECTION=redis`.
- Keep `MESSAGING_REALTIME=true` only when Reverb is configured and reachable from the browser.
- Terminate TLS in Nginx and proxy websocket traffic to the Reverb process.
- Run `php artisan reverb:start` and `php artisan horizon` under Supervisor or systemd.
- The chat UI falls back to HTTP polling only when realtime is disabled in config.
- Database notification fallback now only runs for recipients who are not marked online in messaging presence.

## Reconnect model

- The conversation view loads once via HTTP.
- Live message, read, typing, and conversation summary updates arrive over websocket channels.
- When the socket reconnects, the client requests deltas from the explicit `delta` endpoint and merges them idempotently by message id, UUID, and client temp id.
- HTTP send retries also reuse the original stored message when `client_temp_id` matches, preventing duplicate broadcasts during reconnect races.
