Production Hardening Checklist

Every assertion below is enforced in code at boot or on every request. Confirm posture without reading the source.

This section is intended for: Technical Team, Auditor, Management. Unauthorised access is restricted.

Audit status: Implemented

Every assertion below is enforced in code at boot or on every request. This page consolidates them so an operator can confirm posture without reading the source.

Status: Implemented. Each row cites the file path that enforces it.

Boot-time assertions (src/config/validateEnv.ts)

AssertionBehaviour
JWT_SECRET set, ≥32 charsHard-fail boot in production
JWT_REFRESH_SECRET set, ≥32 charsHard-fail boot in production
DATABASE_URL set (or full PG quartet)Hard-fail boot in production
CORS_ALLOWED_ORIGINS set, no *, every entry valid http(s)Hard-fail boot in production
PUBLIC_URL set and valid http(s)Hard-fail boot in production
PORT parses to integer in [1, 65535]Hard-fail boot
Resend transport: all of (RESEND_API_KEY, ALERT_EMAIL_TO, EMAIL_FROM) or noneHard-fail boot in production if partial
Observability tokens (SENTRY_DSN, RAILWAY_API_TOKEN, VERCEL_API_TOKEN, NEON_API_KEY)Warn-only — boot succeeds
COMMS_* identitiesWarn-only; falls back to @govula.com placeholder

CORS (src/app.ts)

BehaviourWhere
Origins parsed from CORS_ALLOWED_ORIGINSgetCorsOrigins() in src/config/index.ts
Production rejects unknown origins with 403 CORS_DENIEDsrc/app.ts
Wildcard * rejected at bootvalidateEnv.ts
Per-request rejection logged with origin + path metadatalogger.warn('CORS: blocked request from disallowed origin', …)

Helmet / CSP (src/app.ts)

HeaderValue
Content-Security-PolicyStrict — defaultSrc: 'self', objectSrc: 'none', frameSrc: 'none'
Strict-Transport-Securitymax-age=31536000; includeSubDomains; preload
X-Frame-OptionsDENY
X-Content-Type-Optionsnosniff
Referrer-Policyno-referrer

Rate limiting

SurfaceLimiterWhere
Global all-routesexpress-rate-limitsrc/app.ts
Auth (/api/v1/auth/*)authRateLimitersrc/middleware/authRateLimit.ts
Password resetpasswordResetRateLimitersame
Investor trackingper-route limitsrc/routes/investorTracking.ts
Walkthrough requestsper-route limitroute file
Audit exportper-route limitroute file
Per-tenant (opt-in)perTenantRateLimitsrc/middleware/perTenantRateLimit.ts

Known gap (audit F-S6): POST /api/v1/gps/verify only has the global limiter. Tracked as the existing project task "Lock down public peer-onboarding endpoint…".

Tenant isolation (RLS)

AssertionWhere
RLS in STRICT mode (no bypass-on-null)src/migrations/018_strict_rls.sql
app.tenant_id set inside transactionqueryWithTenant() in src/repositories/database.ts
System queries require typed SystemQueryReason + actorqueryAsSystem() same file
Raw getClient() escape hatch hard-throwssrc/repositories/database.ts:509
Cross-tenant aggregates require min-cohort=5industry_benchmarks.cohort_size CHECK >= 5

Audit immutability

LedgerAppend-only mechanism
audit_logPostgres DO INSTEAD NOTHING rule (src/migrations/014_forensic_audit.sql)
tenant_operation_logsame (src/migrations/035_tenant_operations.sql)
operator_audit_eventssame (src/migrations/037_operator_domain.sql)
Hash chain integritySHA-256, replayable via force_audit_replay_validation

Body parsing

BehaviourWhere
Body ≤ 1 MBexpress.json({ limit: '1mb' }) in src/app.ts
Oversized body → 413 (NOT 500)error handler in same file
Malformed JSON → 400 (NOT 500)same
Unknown route → 404 with structured payloadsame

Health endpoints

PathBehaviour
GET /healthUnconditional liveness; never auth-gated; never blocked by middleware. Use this for load balancer healthchecks.
GET /api/v1/healthFull readiness envelope; gated on the boot envelope in production. Use this for "should this instance receive traffic?".

Operator elevation

AssertionWhere
Operator capabilities require explicit elevation over normal sessionsrc/middleware/operatorElevation.ts
Elevation requires reason ≥ 10 charssrc/services/operatorService.ts
Recent-auth check ≤ 30 min, fail-closedsame
Every elevation grant + every capability invocation auditedrecordAuditEvent('operator.elevation.granted', …)

What's NOT enforced (audit gaps)

These are real gaps documented in ../audits/phase1-readiness-audit.md. Tracked as separate project tasks:

  • POST /api/v1/gps/onboard is unauthenticated (F-A1) — HIGH
  • POST /api/v1/gps/verify lacks per-route rate limit (F-A2)
  • body_html rendered with dangerouslySetInnerHTML from operator-controlled content lacks server-side sanitization contract (F-S1)
  • CSRF posture is mixed; no CSRF token model (F-S2) — currently mitigated by Bearer-header default

Manual confirmation

Run the post-deploy verification block from ../production-checklist.md. Every assertion above produces a deterministic HTTP response — no inspection of internal state is required.

Where to read more

Canonical source: docs/deployment/production-hardening.md

This page mirrors the markdown deployment hub on disk. The full markdown source includes additional code blocks, command examples, and embedded reference tables.

Hub index: /docs/deployment

You are here · Deploy · step 15
Backup & Recoverynext step

Validate backup + recovery as part of the pre-flight.

What should I do next?

Activation Flowprimary

continues in "deploy"

Ranked using IA v1 graph + intent map + glossary density (deterministic; no AI inference).