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
358 lines
17 KiB
Python
358 lines
17 KiB
Python
from docx import Document
|
||
from pathlib import Path
|
||
import shutil
|
||
|
||
src = Path(r"D:\1\management\docs\design\RentalDriveGo_Technical_Architecture_and_Investor_Due_Diligence.docx")
|
||
backup = src.with_suffix(".v1.0.backup.docx")
|
||
if not backup.exists():
|
||
shutil.copy2(src, backup)
|
||
print("backup:", backup)
|
||
|
||
doc = Document(str(src))
|
||
|
||
|
||
def set_runs_text(paragraph, text: str) -> None:
|
||
if paragraph.runs:
|
||
paragraph.runs[0].text = text
|
||
for r in paragraph.runs[1:]:
|
||
r.text = ""
|
||
else:
|
||
paragraph.add_run(text)
|
||
|
||
|
||
# --- Title / version updates ---
|
||
for i, p in enumerate(doc.paragraphs[:15]):
|
||
t = p.text.strip()
|
||
if t.startswith("Version 1.0"):
|
||
set_runs_text(
|
||
p,
|
||
"Version 1.1 • 12 August 2026 (addendum update of v1.0 dated 9 August 2026)",
|
||
)
|
||
print(f"updated version para {i}")
|
||
if "Prepared from the supplied" in t:
|
||
set_runs_text(
|
||
p,
|
||
"Prepared from the car_management / management monorepo; v1.1 reflects Phases 0–4 "
|
||
"production-readiness implementation status as of 12 August 2026",
|
||
)
|
||
print(f"updated prepared para {i}")
|
||
|
||
# --- Soft-update executive bottom line ---
|
||
for i, p in enumerate(doc.paragraphs):
|
||
if p.text.startswith("Bottom line"):
|
||
set_runs_text(
|
||
p,
|
||
"Bottom line (updated 12 Aug 2026) RentalDriveGo remains a serious multi-application "
|
||
"rental SaaS with strong domain depth. Since the 9 August 2026 archive review, the monorepo "
|
||
"has been restored and Phases 0–4 of the production-readiness program have landed in "
|
||
"application code and in-repo runbooks: security P0/P1 fixes, dedicated api-worker with "
|
||
"leased outbox, Redis rate-limit/idempotency, object-storage driver, /ready and /metrics, "
|
||
"single plan catalog, OpenAPI coverage gate, cross-tenant tests, and extraction deferred "
|
||
"pending measurement (ADR-003). The platform is still not “production ready” as an investor "
|
||
"claim until clean-runner CI/SCA evidence, Compose multi-replica smoke, restore/alert drills, "
|
||
"soak/pen-test, and §13 checkpoint items are recorded. The accurate frame is now: product + "
|
||
"operational foundations exist in code; remaining capital/ops work is evidence and assurance, "
|
||
"not a greenfield rebuild.",
|
||
)
|
||
print(f"updated bottom line para {i}")
|
||
break
|
||
|
||
# Update investment interpretation cells
|
||
for table in doc.tables:
|
||
for row in table.rows:
|
||
cells = [c.text.strip() for c in row.cells]
|
||
if not cells:
|
||
continue
|
||
dim = cells[0]
|
||
if dim == "Delivery reproducibility" and len(cells) >= 3:
|
||
row.cells[1].text = "Mostly restored in tree"
|
||
row.cells[2].text = (
|
||
"turbo.json, tsconfig.base.json, scripts, Compose, backup/restore present; "
|
||
"clean-runner CI green still needs recorded evidence."
|
||
)
|
||
elif dim == "Scale readiness" and len(cells) >= 3:
|
||
row.cells[1].text = "Improved (code)"
|
||
row.cells[2].text = (
|
||
"api-worker, Redis stores, S3/MinIO driver, readiness/shutdown landed; "
|
||
"two-replica soak evidence still open."
|
||
)
|
||
elif dim == "Operational maturity" and len(cells) >= 3:
|
||
row.cells[1].text = "Baseline in code"
|
||
row.cells[2].text = (
|
||
"/metrics, structured logs, backup smoke, runbooks present; "
|
||
"alert/restore/pen-test drills still open."
|
||
)
|
||
elif dim == "Security design" and len(cells) >= 3:
|
||
row.cells[1].text = "Strengthened"
|
||
row.cells[2].text = (
|
||
"S1–S15 application findings closed or documented; containers fail-closed; "
|
||
"fresh 2FA TTL; review tokens scrubbed; pen-test still required."
|
||
)
|
||
|
||
# Update material findings glance
|
||
for table in doc.tables:
|
||
for row in table.rows:
|
||
texts = [c.text for c in row.cells]
|
||
joined = " | ".join(texts)
|
||
if "turbo.json and tsconfig.base.json are absent" in joined and len(row.cells) >= 3:
|
||
row.cells[0].text = "P0→Mitigated"
|
||
row.cells[1].text = (
|
||
"Monorepo envelope (turbo.json, tsconfig.base.json, scripts, Compose) "
|
||
"restored in the management tree."
|
||
)
|
||
row.cells[2].text = "Remaining: recorded clean-runner CI/smoke evidence."
|
||
elif "21 vulnerabilities" in joined and len(row.cells) >= 3:
|
||
row.cells[0].text = "P0→Open evidence"
|
||
row.cells[1].text = (
|
||
"CI now runs production npm audit (fail on high); "
|
||
"local/registry results still time-sensitive."
|
||
)
|
||
row.cells[2].text = "Clear critical/high on a clean runner or file dated exceptions."
|
||
elif ("Per-tenant container" in joined or "container orchestration" in joined.lower()) and len(
|
||
row.cells
|
||
) >= 3:
|
||
row.cells[0].text = "P0→Mitigated"
|
||
row.cells[1].text = "Container feature fail-closed; admin UI out-of-scope; ADR-001 accepted."
|
||
row.cells[2].text = "Do not re-enable Docker-socket tenant isolation."
|
||
elif "no dispatcher/worker was found" in joined and len(row.cells) >= 3:
|
||
row.cells[0].text = "P1→Mitigated in code"
|
||
row.cells[1].text = "Dedicated api-worker with leased outbox dispatch and Redis realtime publish."
|
||
row.cells[2].text = "Prove under two API replicas + worker in staging."
|
||
elif "Rate limits" in joined and "process-local" in joined.lower() and len(row.cells) >= 3:
|
||
row.cells[0].text = "P1→Mitigated in code"
|
||
row.cells[1].text = (
|
||
"Redis rate-limit store, Redis Carplace idempotency, cron leader lock, S3/local storage driver."
|
||
)
|
||
row.cells[2].text = "Multi-replica correctness evidence still required."
|
||
elif (
|
||
"No complete CI/CD, observability" in joined
|
||
or "graceful shutdown, backup/restore" in joined
|
||
) and len(row.cells) >= 3:
|
||
row.cells[0].text = "P1→Partial"
|
||
row.cells[1].text = (
|
||
"CI security/OpenAPI gates, /ready, /metrics, backup smoke scripts and ops runbooks landed."
|
||
)
|
||
row.cells[2].text = "Alert/restore/pen-test/soak evidence still open."
|
||
|
||
# Update recommendation bullets
|
||
for p in doc.paragraphs:
|
||
if p.text.startswith("Treat the current asset as a capable beta"):
|
||
set_runs_text(
|
||
p,
|
||
"Treat the current asset as a late beta / hardening-stage platform: application foundations "
|
||
"for production readiness are largely implemented; do not claim production-hardened SaaS until "
|
||
"exit evidence (§13) is complete.",
|
||
)
|
||
if p.text.startswith("Condition any production or scale claim"):
|
||
set_runs_text(
|
||
p,
|
||
"Condition any production or scale claim on remaining evidence gates: clean CI/SCA, "
|
||
"two-replica Compose smoke, restore meeting RPO/RTO, alert/failure drill, soak, "
|
||
"independent pen-test, and provider reconciliation sample.",
|
||
)
|
||
if p.text.startswith("Fund a 90-day production-readiness program"):
|
||
set_runs_text(
|
||
p,
|
||
"Continue the funded production-readiness program through evidence close-out; Phase 4 "
|
||
"service extraction remains deferred until measurement gates pass (ADR-003). Reevaluate "
|
||
"extraction only from measured load and ownership boundaries.",
|
||
)
|
||
|
||
# Risk register updates
|
||
risk_updates = {
|
||
"R1": ("Mostly mitigated", "Envelope restored in tree; prove clean-runner CI/smoke."),
|
||
"R2": ("Open (CI policy)", "SCA gate in CI; clear critical/high on clean runner."),
|
||
"R3": ("Mitigated in code", "ADR-001; containerService fail-closed; UI out-of-scope."),
|
||
"R4": ("Mitigated in code", "api-worker + DB leases + Redis publish; prove multi-replica."),
|
||
"R5": ("Mitigated in code", "Redis rate-limit and idempotency stores."),
|
||
"R6": ("Mitigated in code", "Schedules on worker with Redis leader lock."),
|
||
"R7": ("Mitigated in code", "FILE_STORAGE_DRIVER local|s3; prefer object storage in prod."),
|
||
"R8": ("Partial", "Metrics/logs/runbooks in repo; drills still open."),
|
||
"R9": ("Partial", "Privacy data map drafted; owners/DSAR/encryption plan open."),
|
||
"R10": ("Mitigated in code", "packages/types planCatalog + homepage/API consumers + tests."),
|
||
"R11": ("Mitigated in code", "OpenAPI coverage CI gate; /ready and /metrics documented."),
|
||
"R12": ("Partial", "Billing/notification SoT documented; migration convergence ongoing."),
|
||
"R13": ("Open / later", "Shared clients still a Phase 3+ concern."),
|
||
"R14": ("Open / later", "Stabilize CI runners; bounded completion still evidence."),
|
||
}
|
||
|
||
for table in doc.tables:
|
||
for row in table.rows:
|
||
first = row.cells[0].text.strip()
|
||
for rid, (status, action) in risk_updates.items():
|
||
if first.startswith(rid + " ") or first.startswith(rid + "•") or first.startswith(rid + " ·") or first.startswith(rid + " •"):
|
||
if len(row.cells) >= 4:
|
||
ev = row.cells[2].text.strip()
|
||
if "STATUS (12 Aug 2026)" not in ev:
|
||
row.cells[2].text = f"{ev}\nSTATUS (12 Aug 2026): {status}"
|
||
row.cells[3].text = action
|
||
elif len(row.cells) >= 3:
|
||
row.cells[2].text = f"STATUS (12 Aug 2026): {status}. {action}"
|
||
|
||
# Phase status annotations
|
||
phase_status = {
|
||
"Phase 0 — Evidence recovery": (
|
||
"STATUS (12 Aug 2026): Application/envelope code largely complete; "
|
||
"remaining is recorded CI green + Compose smoke evidence."
|
||
),
|
||
"Phase 1 — Correctness and shared state": (
|
||
"STATUS (12 Aug 2026): Core code landed (worker, Redis stores, S3 driver, /ready, shutdown). "
|
||
"Two-replica correctness evidence still open."
|
||
),
|
||
"Phase 2 — Operational control": (
|
||
"STATUS (12 Aug 2026): Metrics, catalog, OpenAPI gate, backup smoke, privacy/SoT docs landed. "
|
||
"Alert/restore/reconciliation drills still open."
|
||
),
|
||
"Phase 3 — Scale and assurance": (
|
||
"STATUS (12 Aug 2026): Cross-tenant suite, soak/chaos scripts, canary/key/pen-test runbooks, "
|
||
"S11–S13 fixes landed. Staging drills and pen-test report still open. RLS deferred (ADR-002)."
|
||
),
|
||
"Phase 4 — Selective evolution": (
|
||
"STATUS (12 Aug 2026): Extraction gates documented (ADR-003). Default decision remains "
|
||
"do not extract microservices until G1–G7 measurement passes."
|
||
),
|
||
}
|
||
|
||
paras = list(doc.paragraphs)
|
||
for idx, p in enumerate(paras):
|
||
for title, status in phase_status.items():
|
||
if p.text.startswith(title):
|
||
insert_after = idx
|
||
for j in range(idx, min(idx + 12, len(paras))):
|
||
if paras[j].text.startswith("Exit evidence"):
|
||
insert_after = j
|
||
break
|
||
if insert_after + 1 < len(paras) and not paras[insert_after + 1].text.strip():
|
||
set_runs_text(paras[insert_after + 1], status)
|
||
elif paras[insert_after].text.startswith("Exit evidence"):
|
||
set_runs_text(paras[insert_after], paras[insert_after].text + " " + status)
|
||
else:
|
||
set_runs_text(p, p.text + " — " + status)
|
||
print("phase status:", title[:48])
|
||
|
||
# Claims not supportable — soft updates
|
||
for p in doc.paragraphs:
|
||
if p.text.startswith("CI-green or reproducibly deployable from the supplied package"):
|
||
set_runs_text(
|
||
p,
|
||
"CI-green or reproducibly deployable without recorded clean-runner evidence "
|
||
"(envelope restored in tree, but attestation still required).",
|
||
)
|
||
if p.text.startswith("Complete OpenAPI coverage or a stable external API contract"):
|
||
set_runs_text(
|
||
p,
|
||
"Perfect OpenAPI coverage (coverage gate exists; completeness still approximate "
|
||
"and must stay green in CI).",
|
||
)
|
||
if p.text.startswith("Guaranteed email, push, SMS, or realtime notification delivery through the modeled outbox"):
|
||
set_runs_text(
|
||
p,
|
||
"Guaranteed multi-channel notification delivery in production without worker soak "
|
||
"evidence (dispatcher exists in code).",
|
||
)
|
||
if p.text.startswith("Per-tenant container isolation or functioning tenant container orchestration"):
|
||
set_runs_text(
|
||
p,
|
||
"Per-tenant container isolation (explicitly disabled and out of production scope — ADR-001).",
|
||
)
|
||
|
||
# --- Append full addendum ---
|
||
doc.add_page_break()
|
||
doc.add_heading("Addendum A — Implementation status (12 August 2026)", level=1)
|
||
intro = doc.add_paragraph()
|
||
intro.add_run(
|
||
"This addendum updates Version 1.0 (9 August 2026) after execution of the production-readiness "
|
||
"program against the management monorepo. It does not replace the original evidence-based findings; "
|
||
"it records what has since been implemented in application code and in-repo runbooks, and what remains "
|
||
"evidence-only before a production-ready claim."
|
||
)
|
||
|
||
doc.add_heading("A.1 Verdict shift", level=2)
|
||
doc.add_paragraph(
|
||
"9 Aug 2026: capable beta / pre-scale; package incomplete; scale-critical paths process-local or missing."
|
||
)
|
||
doc.add_paragraph(
|
||
"12 Aug 2026: late beta / hardening stage. Phases 0–4 application code and runbooks are complete. "
|
||
"Investor “production ready” still requires recorded ops evidence (CI smoke, multi-replica proof, "
|
||
"DR/alert drills, soak, pen-test)."
|
||
)
|
||
|
||
doc.add_heading("A.2 Phase implementation summary", level=2)
|
||
phases = [
|
||
(
|
||
"Phase 0 — Security & envelope",
|
||
"Team/admin secret scrubbing; hashed invites; containers fail-closed (ADR-001); "
|
||
"redirect/payment allowlists; employee email uniqueness; hash-only reset/verify tokens; "
|
||
"env scrub; CI security:static + npm audit gate.",
|
||
),
|
||
(
|
||
"Phase 1 — Replica-safe shared state",
|
||
"Dedicated api-worker; outbox DB leases; Redis publish; Redis rate-limit & Carplace idempotency; "
|
||
"FILE_STORAGE_DRIVER local|s3; GET /ready; graceful shutdown; ENABLE_EMBEDDED_JOBS gated.",
|
||
),
|
||
(
|
||
"Phase 2 — Operational control",
|
||
"Structured logs + GET /metrics; planCatalog single source; OpenAPI coverage CI; "
|
||
"backup smoke + RPO/RTO checklist; privacy map; billing/notification source-of-truth docs.",
|
||
),
|
||
(
|
||
"Phase 3 — Scale & assurance",
|
||
"Cross-tenant isolation suite; S11 reviewToken scrub; S12 single-use payment consume; "
|
||
"S13 fresh 2FA TTL; soak/chaos scripts; canary/key-rotation/pen-test docs; RLS deferred (ADR-002).",
|
||
),
|
||
(
|
||
"Phase 4 — Selective evolution",
|
||
"No microservice extract. ADR-003 + extraction gates G1–G7 + measurement templates. "
|
||
"Default: stay modular monolith + api-worker.",
|
||
),
|
||
]
|
||
for title, body in phases:
|
||
p = doc.add_paragraph()
|
||
run = p.add_run(title + ". ")
|
||
run.bold = True
|
||
p.add_run(body)
|
||
|
||
doc.add_heading("A.3 Architecture topology (current intent)", level=2)
|
||
doc.add_paragraph(
|
||
"Traefik → API × N → PostgreSQL; API and worker share Redis (rate limit, idempotency, pub/sub, locks); "
|
||
"api-worker owns outbox/cron; files via local disk or S3/MinIO. Ops endpoints: /health, /ready, /metrics."
|
||
)
|
||
|
||
doc.add_heading("A.4 Security findings S1–S15", level=2)
|
||
doc.add_paragraph(
|
||
"Application findings S1–S15 from the follow-on security review are fixed or documented in code "
|
||
"(including S9 proxy-trust documentation, S11–S13). Independent penetration testing remains an open "
|
||
"Phase 3 evidence item. See docs/design/SECURITY_DESIGN_UPDATES.md and "
|
||
"docs/ops/RentalDriveGo_Production_Readiness_Plan.md §3."
|
||
)
|
||
|
||
doc.add_heading("A.5 Remaining evidence before production-ready claim", level=2)
|
||
for item in [
|
||
"Clean-runner: npm ci → generate → lint → type-check → test → build with CI green and SCA clear/exceptioned.",
|
||
"Compose smoke: two API replicas + worker + Postgres + Redis; booking/payment/notification/file correctness.",
|
||
"Phase 2 drills: staging alert fired once; dated restore meeting RPO/RTO; provider reconciliation sample; privacy owners.",
|
||
"Phase 3 drills: soak + failure injection; pen-test report under security-reports/; canary or rollback record; key-rotation drill.",
|
||
"Phase 4: fill measurement template; default decision remains do not extract.",
|
||
]:
|
||
doc.add_paragraph(item, style="List Bullet")
|
||
|
||
doc.add_heading("A.6 Design documentation pointers", level=2)
|
||
for item in [
|
||
"docs/design/README.md — index of production-readiness design updates",
|
||
"docs/design/PRODUCTION_READINESS_IMPLEMENTED.md — phase-by-phase landed work",
|
||
"docs/design/RUNTIME_AND_OPS_SURFACE.md — worker, metrics, env knobs",
|
||
"docs/ops/RentalDriveGo_Production_Readiness_Plan.md — living execution plan and exit checkboxes",
|
||
"docs/ADR-001-disable-per-tenant-containers.md",
|
||
"docs/ADR-002-defer-postgres-rls.md",
|
||
"docs/ADR-003-defer-service-extraction.md",
|
||
]:
|
||
doc.add_paragraph(item, style="List Bullet")
|
||
|
||
doc.add_paragraph(
|
||
"End of Addendum A. Original sections 1–17 remain the baseline diligence narrative from 9 August 2026, "
|
||
"as amended inline above where statuses were refreshed."
|
||
)
|
||
|
||
doc.save(str(src))
|
||
print("saved", src, "size", src.stat().st_size)
|