Technical docs
Operations Runtime
Public reference generated from tech docs/operations-runtime.md.
Overview
Support-facing runtime notes confirmed in current backend code.
Sessions and cookies
* Main app and realtime server both use `express-session` with `connect-redis`. * Relevant env vars: * `SESSION_COOKIE_NAME` default: `sessionId` * `SESSION_SECRET` * `COOKIE_TTL` * `COOKIE_DOMAIN` * `REDIS_SESSION_HOST` * `REDIS_SESSION_PORT` * `REDIS_SESSION_PREFIX` * Session cookie defaults: * `sameSite: lax` * `httpOnly: true` * `secure: true` in production * Important TTL nuance: * cookie max-age defaults to `7 days` unless `COOKIE_TTL` overrides it * Redis session-store TTL is hard-coded to `24 hours` * `/api/init/whoami` also self-heals org selection: * if the user has no `currentOrganization`, it selects the first org * if the user has no orgs at all, it creates `My Organization` with `2000` credits
Health endpoints
* Main app health endpoint: * `GET /health` * returns `status` and `timestamp` * in non-production, also returns `env`, `session`, and `uptime` * Realtime server health endpoint: * `GET /chat/realtime/health` * returns `status`, `service: realtime`, and `timestamp`
WebSocket token TTLs
* User WS tokens use `COOKIE_TTL`, defaulting to `7 days`. * Webchat WS tokens use `COOKIE_TTL` when set, otherwise default to `24 hours`. * Webchat JWT session tokens use `WEBCHAT_JWT_TTL`, defaulting to `7 days`.
Widget snippet domain selection
* Generated widget snippets start from `API_DOMAIN`. * If org webchat settings set `widgetDomain = proxy` and `API_PROXY_DOMAIN` exists, snippets use the proxy domain instead. * Current snippets load `/widget/alloy-webchat-widget.js` and initialize with: * `apiKey` * `eventId` * `eventId` is routing metadata for the widget entry point. The runtime execution graph still starts from the published workflow or employee workflow tied to that event.
Realtime session handoff
* Pending realtime session configs are stored in Redis under: * `${REDIS_PREFIX || 'alloy_dev'}realtime:{sessionId}` * TTL is `20 minutes`. * Configs are one-time use and are deleted on first successful retrieval. * Ally realtime session creation is: * `POST /chat/realtime/ally/create-session/:organization_id` * Ally realtime runs seed runtime context with: * `targetOrganizationId` * `userId`
Request and upload limits
* Main app request-body limits: * JSON: `70mb` * URL-encoded: `70mb` * HTTP server timeouts for both app and realtime: * `requestTimeout = 600000` * `headersTimeout = 600000` * `keepAliveTimeout = 5000` * Storage uploads still enforce `10 MB` per file. * Internal-chat attachments are limited to: * max `5` files * max `10 MB` each * allowed MIME families: images, PDF, SQLite, plain text, XML
Shutdown and error signaling
* Both servers use `http-graceful-shutdown`. * Shutdown timeout is `450000 ms`. * Cleanup closes: * `redisClient` * `redisQueueClient` * Sequelize * `uncaughtException` and `unhandledRejection` are reported to Sentry and `telegramError`. * Telegram delivery requires: * `TELEGRAM_BOT_API_KEY` * `TELEGRAM_CHAT_ID` * Optional Telegram thread routing: * `TELEGRAM_EVENTS_THREAD_ID` * `TELEGRAM_ERRORS_THREAD_ID` * `TELEGRAM_FEEDBACK_THREAD_ID` * `TELEGRAM_WARNINGS_THREAD_ID`
Quick support checks
* Session issues: * verify Redis availability * compare cookie TTL vs Redis store TTL * verify cookie domain and allowed origins * Wrong widget snippet domain: * check org webchat widget settings plus `API_DOMAIN` and `API_PROXY_DOMAIN` * Realtime connect failures: * check the pending Redis key has not expired or been consumed already * confirm the workflow/voice models still exist * Missing Telegram alerts: * verify bot token, chat ID, optional thread IDs, and bot access to the target chat