# Production readiness — what was implemented **Date:** 2026-08-12 **Code root:** monorepo `apps/*`, `packages/*` **Plan:** `docs/ops/RentalDriveGo_Production_Readiness_Plan.md` This document is the design-facing summary of work already landed. It is not a backlog. --- ## Architecture decision (unchanged) Keep a **modular Express monolith** plus a dedicated **job worker process**. Do not split payments/webhooks/media into microservices until measurement gates pass (ADR-003). ``` [Traefik] → [API × N] → PostgreSQL ↓ ↑ [Redis] [api-worker] ↓ [local disk | S3/MinIO] ``` --- ## Phase 0 — Security & envelope | Area | Design outcome | Primary paths | |------|----------------|---------------| | Team API secrets | Safe presenters; no `passwordHash` / raw reset tokens in responses | `apps/api/src/services/teamService.ts` | | Invite tokens | Stored as SHA-256 hashes | `teamService.ts` | | Admin presenters | Scrub reset/verification secrets | `admin.presenter.ts` | | Per-tenant Docker | Feature **fail-closed**; UI out-of-scope | `containerService.ts`, ADR-001 | | Login redirects | Relative same-origin allowlist only | dashboard `SignInForm` | | Payment return URLs | Authenticated checkout allowlists | `paymentRedirects.ts` | | Admin slugs | Validated / slugified | admin schemas/repo | | Employee email | `@@unique([companyId, email])`; ambiguous login fails closed | Prisma + auth repo | | Reset / email verify tokens | Hash-only lookup (no raw dual-match) | employee/admin repos | | Env templates | Scrubbed of real-looking secrets | `.env.example`, docker env samples | | CI hygiene | `security:static` + production `npm audit` gate | `.gitea/workflows/test.yml` | --- ## Phase 1 — Replica-safe shared state | Area | Design outcome | Primary paths | |------|----------------|---------------| | Job plane | Dedicated `api-worker`; API embeds jobs only if `ENABLE_EMBEDDED_JOBS=true` | `apps/api/src/workers/` | | Notification outbox | DB leases (`lockedAt` / `lockedBy` / `attempts` / `availableAt`) | `notificationService` + migration | | Realtime | Redis publish on IN_APP delivery | worker / notification service | | Rate limits | Shared Redis store | `redisRateLimitStore.ts` | | Carplace idempotency | Redis-backed store | `idempotencyStore.ts` | | Files | `FILE_STORAGE_DRIVER=local\|s3` (+ MinIO compose profile) | `lib/storage`, `objectStorage` | | Readiness | `GET /ready` checks DB, Redis, storage | `app.ts` | | Shutdown | SIGTERM drains API and worker | `index.ts`, `workers/index.ts` | --- ## Phase 2 — Operational control (code baselines) | Area | Design outcome | Primary paths | |------|----------------|---------------| | Metrics / logs | Structured JSON access logs; Prometheus text at `GET /metrics` | `opsMetrics.ts`, `app.ts` | | Worker metrics | Optional `WORKER_METRICS_PORT` exposes `/metrics` + `/health` | `workers/index.ts` | | Plan catalog | Single source in `@rentaldrivego/types` | `packages/types/src/planCatalog.ts` | | Homepage pricing | Imports catalog (no hard-coded MAD amounts) | `apps/homepage/.../pricing-config.ts` | | OpenAPI gate | Coverage script + CI step | `scripts/check-openapi-coverage.mjs` | | Backup smoke | Artifact checker + RPO/RTO checklist | `scripts/backup-restore-*` | | Privacy / SoT docs | Baseline maps | `docs/PRIVACY_DATA_MAP.md`, `docs/BILLING_NOTIFICATION_SOURCE_OF_TRUTH.md` | **Still evidence-only:** staging alert fire, dated restore drill, provider reconciliation sample, privacy owners. --- ## Phase 3 — Scale & assurance (code / runbooks) | Area | Design outcome | Primary paths | |------|----------------|---------------| | Cross-tenant suite | Vehicles, customers, reservations, offers, team, payments negatives | `cross-tenant-isolation.test.ts` | | S11 | `reviewToken` omitted from API JSON | reservation presenter, review service | | S12 | Public booking token: GET does not burn; payment **consumes** once | `site.service.ts` / `site.repo.ts` | | S13 | Fresh admin 2FA max-age (default 30 minutes) | `requireFreshAdmin2FA` | | Soak / chaos | Node soak probe + optional k6; failure-injection helper | `scripts/load/`, `scripts/chaos/` | | Canary / keys / pen-test | Runbooks and scope pack | `docs/ops/`, `docs/security/pen-test-scope.md` | | Postgres RLS | Explicitly deferred | ADR-002 | **Still evidence-only:** soak/chaos drill records, pen-test report, canary + key-rotation drills. --- ## Phase 4 — Extract only if measured | Area | Design outcome | |------|----------------| | Default | Stay on monolith + `api-worker` | | Gates | G1–G7 in `docs/ops/phase4-extraction-gates.md` | | Candidates | Notifications worker deployable, payments/webhooks, media — **blocked** until measurement | | Code change | None required for “phase complete”; ADR-003 + templates only | --- ## Explicit non-goals (still) - Claiming production ready without §13 evidence - Shipping per-tenant container orchestration - Microservices rewrite without gate evidence - Marketing KYC / OCR authenticity beyond license date checks