Production Readiness
Security headers, rate limiting, observability, and the go-live checklist for ObjectStack runtimes.
Production Readiness
@objectstack/runtime ships first-class primitives for the cross-cutting
concerns every production deployment needs: HTTP hardening, rate limiting,
metrics, error reporting, and request-id correlation. Everything is
pluggable — defaults are safe, opt-in is gradual, and the framework
takes no hard dependency on Prometheus / OTel / Sentry / Redis.
This guide is the high-level overview. For the full reference (header defaults, adapter recipes, go-live checklist) follow the deep-dive links.
| Concern | Default | Deep dive |
|---|---|---|
| Security response headers (CSP / XCTO / X-Frame-Options / …) | On | HARDENING.md |
| HSTS | Off (opt-in once TLS is confirmed) | HARDENING.md |
| Rate limiting (token bucket) | Off (opt-in via adapter) | HARDENING.md |
| CSRF | Adapter-layer (bearer-auth = N/A) | HARDENING.md |
| Auth / session / JWT lifecycle | On via @objectstack/plugin-auth (better-auth) | HARDENING.md |
| Metrics (counter / histogram / gauge) | Noop (no adapter) | OBSERVABILITY.md |
| Error reporting (5xx only) | Noop (no adapter) | OBSERVABILITY.md |
Request id (X-Request-Id) | Auto-generated when enabled | OBSERVABILITY.md |
W3C Trace Context (traceparent) | Parser exported; SDK wiring is host's job | OBSERVABILITY.md |
Wiring everything together
A typical production server enables all four:
import { createDispatcherPlugin } from '@objectstack/runtime';
import { promMetrics } from './adapters/prom-metrics.js'; // your code
import { sentryReporter } from './adapters/sentry.js'; // your code
const dispatcher = createDispatcherPlugin({
// Hardening
securityHeaders: {
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
// CSP defaults to deny-all (API server). Override here if you serve
// a SPA from the same origin.
},
// Observability
observability: {
metrics: promMetrics,
errorReporter: sentryReporter,
},
});That's it — every route the dispatcher mounts now:
- Sends conservative security headers.
- Echoes
X-Request-Id(honored from caller, or freshly minted). - Emits
http_requests_total{method,route,status}andhttp_request_duration_msmetrics. - Reports 5xx exceptions to Sentry (or your reporter) with the request id attached.
Rate limiting is the one piece you wire at the adapter layer (Fastify preHandler, Hono middleware, etc.) because that's where you have reliable access to the caller's IP and authenticated identity. See the HARDENING.md recipes.
Go-live checklist
- HSTS enabled (after TLS is confirmed and you accept the lock-in).
- CSP tuned for your serving topology (deny-all API, looser for SPA-on-same-origin).
- Rate limit configured at the adapter for
/auth/*, write verbs, and read verbs (auth bucket should be ~10/min/IP). - Metrics adapter wired;
/metricsendpoint (Prom) or OTel exporter producing data; alerts wired for error rate + p95 latency per route. - Error reporter wired; synthetic 5xx test reaches Sentry / Datadog / Rollbar.
- Log records include
requestIdand cross-check with the responseX-Request-Idheader. - better-auth session TTL / refresh / revoke verified (curl checklist in HARDENING.md).
- Cross-tenant negative tests in CI.
- Multi-org deployments: tenant isolation is active, not degraded —
confirm
features.degradedTenancyisfalsein/auth/config. A deployment requesting multi-org without@objectstack/organizationsnow refuses to boot unlessOS_ALLOW_DEGRADED_TENANCY=1; never set that flag in production. See Tenancy Modes & Membership. - Backup / restore drill documented and tested.
- Data-retention windows reviewed (ADR-0057): the platform's default
lifecycledeclarations bound telemetry (activity 14d, job runs 30d, notifications 90d, audit 90d-hot); extend per environment/tenant via thelifecycle.retention_overridessetting before go-live if your compliance regime needs longer, and register anarchivedatasource if audit data must move to cold storage instead of being retained hot.
What's NOT in the runtime (yet)
- OTel context propagation. We export
parseTraceparent/formatTraceparentso the host can wiretraceparentinto its OTel SDK, but we don't bundle the SDK itself. The OTel API surface is large and host-specific (Node vs. edge vs. browser). - A Prometheus
/metricsendpoint. Adapters mount their own scrape endpoint after wiring theMetricsRegistry. We give you the recipe, not the endpoint, because TLS / auth / path conventions vary. - A built-in audit log immutability layer.
@objectstack/plugin-auditwritessys_audit_logrecords via ObjectQL afterInsert/afterUpdate/afterDelete hooks; durable storage and tamper-evidence are the host's choice (append-only S3, immudb, etc.).