patx/relay-lang

# Linux deployment

Use a TLS reverse proxy and a dedicated MongoDB database/user. Application source is trusted code with filesystem and network access. Relay is not an untrusted-code sandbox.

```sh
cargo build --release --locked
RELAY_ENV=production \
RELAY_BIND=127.0.0.1:8080 \
RELAY_PUBLIC_ORIGIN=https://example.com \
RELAY_TRUSTED_PROXIES=127.0.0.1 \
RELAY_MANAGEMENT_BIND=127.0.0.1:9090 \
RELAY_MONGO_URI='mongodb://localhost:27017' \
./target/release/relay run examples/twitter_clone/app.ry
```

Provide database credentials and SMTP credentials using your deployment's secret mechanism. Do not commit them. `RELAY_MONGO_URI` and `RELAY_MONGO_DATABASE` are conventions used by the examples; application code reads them through `env.get`/`env.require`.

| Setting | Default | Meaning |
|---|---|---|
| `RELAY_ENV` | `development` | `production` requires MongoDB sessions, HTTPS public origin and Secure cookies |
| `RELAY_BIND` | `127.0.0.1:8080` | Service socket |
| `RELAY_PUBLIC_ORIGIN` | unset | Exact browser origin, without trailing slash |
| `RELAY_TRUSTED_PROXIES` | none | Comma-separated individual proxy IP addresses; no CIDR expansion |
| `RELAY_REQUEST_TIMEOUT_MS` | 30000 | HTTP handler deadline |
| `RELAY_MAX_REQUESTS` | 256 | Concurrent HTTP admission cap; excess receives 503 |
| `RELAY_SHUTDOWN_GRACE_MS` | 30000 | Graceful drain budget |
| `RELAY_MANAGEMENT_BIND` | disabled | Separate health/readiness/metrics listener; bind privately |

Uploads default to a 10 MiB request limit and 5 MiB file limit. Override with `app.uploads(...)`. MIME allowlists validate declared MIME types, not file contents. HTTP client connect/total timeouts are 10/30 seconds; SMTP has a 30-second transport timeout. MongoDB queries are bounded and have a 30-second server execution limit where supported.

SIGTERM/SIGINT stops readiness and new connections, drains work within the grace period, and cancels remaining work. Configure the process supervisor/container stop timeout slightly above Relay's grace period. In-process background work does not survive restarts; use an external durable queue when that guarantee is needed.

Management endpoints are `/healthz`, `/readyz`, and `/metrics`. Readiness indicates that this process has completed startup and is accepting requests; it does not continuously probe MongoDB. Metrics expose request totals, active requests, server errors, cumulative duration and background task count. Logs are JSON lines on stderr. Keep the management listener off public networks.

Cross-origin unsafe browser requests are denied unless they match the configured public origin. This release does not enable arbitrary cross-origin credentialed APIs. For development, the current HTTP host is accepted. Forwarded headers are trusted only when the TCP peer matches an explicitly configured proxy IP. Direct production exposure without a TLS proxy is unsupported.

Scale by running multiple processes behind the proxy against the same session collection. Keep deployments on the same session schema. Session conflicts return 409 rather than silently dropping updates. Database schema/index changes belong to the application and should be planned separately from binary rollout.

## Verification

```sh
cargo test --locked
cargo build --release --locked
node tools/local-validation.mjs mongo-tests
node tools/local-validation.mjs integration
node tools/local-validation.mjs soak 3600
```

Local validation requires `mongod` and Node.js. Each invocation creates an isolated temporary database directory, stops only its own processes, and retains test data/logs for inspection. Soak reports include the binary SHA-256, endpoint timing histograms, memory samples, error counts and shutdown result. A short smoke run is not the release soak. Do not claim a release has passed until its exact binary completes the full run and the remaining release checks pass.