Skip to content

Deployment

Radioso’s production contract is a multi-service deployment. The backend, frontend, and document worker are separate runtime units, and the docs portal should stay separate as well.

Production contract

  • independent image per service
  • independent Cloud Run service for backend, frontend, and worker
  • Cloud SQL for application state
  • GCS for uploaded document source files
  • Cloud Tasks for request-driven worker dispatch
  • Secret Manager for runtime secrets

Required configuration categories

At minimum, a production deployment needs:

  • database connectivity
  • model provider credentials
  • session and token secrets
  • storage configuration for uploaded files
  • public base URLs for customer-facing flows such as public chat and Enterprise Edition modules

Relevant runtime flags are defined in .env.example and enforced by backend/src/app/config/env.ts.

Radioso’s own MCP server is a deployment-level setting: set RADIOSO_MCP_ENABLED to turn it on, and set RADIOSO_MCP_STANDALONE depending on whether MCP should run merged into the backend or as its own process. See MCP server for both deployment shapes and the credentials each one needs.

Enterprise Edition deployment

Enterprise Edition

Enterprise deployments use the same Cloud Run services, but the deploy workflow builds the images with radioso_edition: enterprise. In practice, that does two things:

  • the backend image installs @radioso/enterprise-backend-module
  • Terraform injects RADIOSO_APPLICATION_MODULES and edition flags into Cloud Run

Keep app_base_url_override set to the public frontend origin after the first service rollout, for example https://app.example.com. If you use the included Terraform workflow, set the GitHub environment variable APP_BASE_URL to that origin. If you deploy another way, set the backend runtime APP_BASE_URL to the same origin. Terraform also forwards this value as RADIOSO_WIDGET_ORIGIN. Password reset emails, email verification emails, and the website embed snippet use these values when they build hosted links.

Once accounts start creating content, cap how much of it an account can index and how many answers it can generate — see Enterprise usage limits for the meters, the admin API, and the 429 responses callers see at a cap.

Required secrets

The Terraform workflow expects these GitHub environment secrets for each deployed environment:

  • OPENAI_API_KEY
  • SESSION_COOKIE_SECRET
  • WORKSPACE_TOKEN_SECRET
  • PUBLIC_CHAT_SESSION_SECRET
  • CONNECTOR_ENCRYPTION_KEY
  • RESEND_MAIL_API_KEY
  • POSTHOG_API_KEY

PUBLIC_CHAT_SESSION_SECRET signs public chat session tokens for anonymous chat links and website embeds. In Terraform this maps to public_chat_session_secret, which is stored in Secret Manager and injected into the backend as PUBLIC_CHAT_SESSION_SECRET.

WORKSPACE_TOKEN_SECRET signs workspace API tokens and derives the per-agent signing key a workspace admin can reveal so their website’s own backend can prove signed visitor identity for embedded chat.

Set MAIL_FROM_EMAIL to a verified sender address. MAIL_FROM_NAME is optional and defaults to Radioso.

The included staging and live Terraform environments enable PostHog error reporting with ERROR_SINKS=audit,posthog. Staging also sends product analytics to PostHog with PRODUCT_ANALYTICS_SINKS=audit,posthog. Set POSTHOG_API_KEY for each environment. POSTHOG_HOST defaults to the US ingestion host and can be overridden for another PostHog region or a self-hosted instance.

Public chat rate limits

Public chat and website embed rate limits are operator tuning knobs, not workspace settings. When unset, the backend uses built-in defaults.

  • PUBLIC_CHAT_RATE_LIMIT_WINDOW_MS
  • PUBLIC_CHAT_SESSION_RATE_LIMIT_MAX_ATTEMPTS
  • PUBLIC_CHAT_GLOBAL_RATE_LIMIT_MAX_ATTEMPTS

The session limit applies to a visitor session. The global limit applies across public chat traffic for the process, and both are process-wide: Radioso does not read a per-workspace override, so set them to values every workspace on this deployment can share.

Runtime separation

The backend owns migrations, auth, retrieval, chat, and API routes. The worker owns queued document processing. Keep those services independently deployable and independently scalable.

That separation matters because worker traffic behaves differently from chat traffic:

  • worker jobs are durable and retryable
  • chat is synchronous and user-visible
  • worker resource pressure should not degrade app responsiveness

In the hosted Cloud Run environments, the backend and frontend scale to zero when idle. The document worker also defaults to worker_min_instances = 0 and is invoked by Cloud Tasks when document work is queued. Raise worker_min_instances only when an environment needs a continuously warm polling fallback for queue recovery.

Startup migrations

The backend runs SQL migrations before it binds the HTTP port. This is intentional: the API should not report healthy or serve traffic until the schema matches the running code.

Workers do not apply SQL migrations. They only check for pending migrations before starting document or crawl work. If a worker starts but the backend revision does not, treat the backend startup migration path as the first thing to inspect.

Startup migration metadata checks use separate lock and statement timeout budgets:

  • DB_MIGRATION_LOCK_TIMEOUT_MS
  • DB_MIGRATION_STATEMENT_TIMEOUT_MS

In practice, a blocked migration metadata check fails with an application log that names startup migrations as the failing phase, rather than looking only like a platform port-listen failure. A lock timeout usually means another database session is holding or waiting on the migration metadata table. The migration SQL body disables those local metadata timeouts so large index builds and backfills can still finish.

The backend owns migrations during startup; there is no separate pre-deploy migration job.

Docs portal deployment

The docs portal is its own Next.js app under docs-portal/. It syncs the backend OpenAPI document during build and should be deployed as a separate public service instead of being mounted into the product frontend.

Rollout checklist

  1. Apply database migrations before or during backend rollout.
  2. Confirm backend can reach Cloud SQL and storage.
  3. Confirm worker runtime can claim or receive jobs.
  4. Confirm frontend points at the current backend service.
  5. Confirm public URLs used for auth and embed flows are correct.
  6. Confirm docs portal build synced the current OpenAPI document.
i

If the app is live but document uploads never become searchable, treat that as a worker-path or dispatch-path incident first.

  • Self-hosting operations — backup, restore, and upgrade steps for deployments you run yourself, including the migration-startup incident playbook this page’s startup-migration behavior feeds into.
  • Enterprise usage limits — cap indexed storage, monthly content, and monthly answers per account.
  • Deployment topology — how the backend, frontend, and worker services relate at runtime.