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
107 lines
5.0 KiB
Markdown
107 lines
5.0 KiB
Markdown
# 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
|