8fc88ffc14
Build & Push / Pipeline Tests (push) Failing after 59s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 51s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
5.0 KiB
5.0 KiB
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