From 2a4dadd5a79dd602cd7498268a8a4001ee954cae Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 2 Jun 2026 17:50:42 +0200 Subject: [PATCH] docs(launch): execute-ready initial-deployment runbook Locked decisions (Postgres=own, deploy dir /root/docker-compose/pn-crm, DB/Redis localhost-only), prerequisites checklist, ordered gated phases (recon -> CRM -> data -> Documenso -> website cutover), rollback anchors. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/deployment-plan.md | 69 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/docs/deployment-plan.md b/docs/deployment-plan.md index 6df51869..7c8d1d38 100644 --- a/docs/deployment-plan.md +++ b/docs/deployment-plan.md @@ -307,3 +307,72 @@ SMTP + alert recipients stay until `WEBSITE_INQUIRY_EMAILS_DISABLED` is set. - residential templates plus a new contact-form alert template, hooked into `/api/public/website-inquiries`. New website env vars documented above. CRM tsc-clean + unit test added; website berth/UTM vue-tsc-clean. Nothing deployed. +- 2026-06-02 (later): in-app notifications for website submissions + the + structured notification-recipient resolver (emails/users/roles/everyone, + backward-compatible) + the admin recipient-picker UI all shipped on the + `feat/website-intake-email-ownership` branch (CRM repo). Contact-form client + confirmation added on BOTH the website (gated by `WEBSITE_INQUIRY_EMAILS_DISABLED`) + and the CRM (gated by `website_intake_email_enabled`). tsc-clean; full vitest + suite (1570) green. Picker live browser-verify pending a dev server. Branch is + 4 commits ahead of `main`, not merged, not pushed. + +--- + +## Initial Deployment Runbook — execute-ready (assembled 2026-06-02) + +> The single ordered checklist for go-live; detailed step content is in Phase 1 +> / Phase 2 above + Initiative 5 (`launch-readiness.md`). **Guardrail stands: no +> prod-server mutation without per-action approval; reads/recon are free.** Per +> Matt (2026-06-02): assemble ALL inputs + the full plan before executing +> anything, including recon. + +### Locked decisions + +- **CRM Postgres:** OWN — compose-default `postgres:16`, isolated `pgdata`. +- **Deploy dir:** `/root/docker-compose/pn-crm/` (matches the other compose folders). +- **DB/Redis exposure:** bind to `127.0.0.1` ONLY — no public ports (the Documenso + `5432` public-exposure + brute-force lesson; the R1 port scan confirms). +- **Initial image:** include the email-ownership work — merge + `feat/website-intake-email-ownership` -> `main` -> push -> CI builds -> pull. + It is all flag-OFF by default, so it ships dormant + safe. (Alternative on + record: deploy `main` as-is, merge before the website cutover flip.) + +### Prerequisites — gather BEFORE executing + +| Need | For | Status | +| -------------------------------------------------------- | ---------------------------------------- | ------------------------ | +| SSH `stefan@45.142.177.246:22022` (key) | all recon + deploy | have | +| prod root pass (`su`) | docker / nginx / certbot | VERIFY (creds file) | +| Gitea registry pull token | `docker login` -> pull crm images | NEED (generate) | +| `WEBSITE_INTAKE_SECRET` (shared) | CRM `.env` + website `CRM_INTAKE_SECRET` | generate at P1 | +| Documenso API token + webhook secret | CRM `.env` (login `matt@portnimara.com`) | NEED | +| MinIO creds (endpoint/key/secret/bucket) for the new CRM | CRM `.env` storage | confirm (creds §3) | +| Legacy MinIO read creds | EOI backfill (D2) | NEED | +| Website-server root pass | Phase 4 env wiring | you provide at that step | +| Maintenance window | Documenso restart | schedule | + +### Ordered steps (each gated) + +- **Phase 0 [recon]** R1 port scan (external + internal listeners) · R2 NocoDB + + Documenso drift vs the 2026-06-01 pull · R3 fresh read-only Documenso `pg_dump` + -> re-run the `1.13.1->2.11.0` clone dry-run (final "won't break" check). +- **Phase 1 [APPROVAL]** P1 prod `.env` -> P2 `/root/docker-compose/pn-crm` + (localhost-bound DB/Redis) -> P3 nginx (HTTP-first) -> P4 + `certbot --nginx -d crm.portnimara.com` -> P5 `docker login` + pull + up -> P6 + schema + seed port/admin -> P7 verify (health, login, berths, socket.io). +- **Phase 2 [APPROVAL]** D1 load migrated data -> D2 MinIO EOI backfill -> D3 + reconcile counts. +- **Phase 3 [APPROVAL · VITAL · together]** backups (pg_dump + cold volume + snapshot + cert + MinIO inventory, off-box) -> staged `1.13.1->2.0.0->2.11.0` + -> verify (login, existing envelope renders, test send, webhook reaches CRM, + CRM stays on v1 API) -> rollback ready. +- **Phase 4 [APPROVAL]** website env wiring on the other server -> cutover flips + (`CRM_INTAKE_URL`/`SECRET` on; then `website_intake_email_enabled` ON + + `WEBSITE_INQUIRY_EMAILS_DISABLED=1`; then `CRM_BERTHS_ENABLED=1`). + +### Rollback anchors + +- CRM: `docker compose -f docker-compose.prod.yml down` — the pn-crm stack is + isolated (own Postgres), zero impact on the other apps on the box. +- Documenso: revert the image tag + restore the cold volume snapshot / pg_dump. +- Website: unset the `CRM_*` env vars -> instant revert to NocoDB + website email.