# Phase 10 — Production Deployment Gates 4-9, 15-16. Covers production infrastructure, network security, DNS/HTTPS, database productionization, Stripe LIVE configuration, Google Workspace production email, observability, and backups/restore. ## Hardware status — PRODUCTION DEPLOYMENT BLOCKED — SERVER REQUIRED Verified, not assumed: `infra/terraform/` has no real `terraform.tfvars` (only `terraform.tfvars.example`) and no `.tfstate` file anywhere in the repo or working tree — `tofu apply` has never been run against real infrastructure. `infra/ansible/group_vars/ production.yml` still holds literal, unfilled placeholders: `platform_ip: __PLATFORM_VM_IP__`, `lab_host_ip: __LAB_HOST_VM_IP__`, `proxmox_mgmt_cidr: __PROXMOX_HOST_MGMT_CIDR__`. No SSH config, known-hosts entry, or inventory file on this workstation references a real `rn-platform-01`/`rn-lab-host-01`/Proxmox host. **The dedicated RootNode Academy production server has not been purchased or provisioned.** Per Phase 10's own explicit instruction, this phase does not fake a production deployment against placeholder infrastructure. Everything below is preparation, validation, and rehearsal — genuinely useful the moment real hardware exists, but none of it is a live deployment. ## What WAS done this phase (all safe, all pre-hardware) - **Gate 4 — IaC validated**: `tofu validate` (OpenTofu, the Terraform-compatible tool actually installed) passes cleanly against `infra/terraform/`'s existing Proxmox provider config — no redesign, the existing config is syntactically sound and ready for real `terraform.tfvars`. `ansible-playbook site.yml --syntax-check -i inventory` passes cleanly against `infra/ ansible/`'s existing `site.yml` and its `firewall`/`docker-tls`/`platform`/`lab-host`/ `monitoring-agent`/`backup`/`common` roles (all present from Phase 4/4.1, unmodified). - **Gate 5 — network security architecture reviewed, unchanged**: RFC1918 egress denial/allowlisting present in `platform/provisioner/src/egress.js`/`lifecycle.js` (Provisioner owns lab-container network policy); mTLS wiring present in `infra/ansible/roles/docker-tls/` and referenced by `gateway.env.j2`; the `firewall` Ansible role exists for both host tiers. All of this is existing Phase 4/4.1 work, re-confirmed present and un-redesigned — none of it can be verified AGAINST a real host without one existing. - **Gate 6 — DNS/HTTPS audited (read-only)**: `rootnodeacademy.com` **is already live** — resolves via Cloudflare (`172.67.141.39`, `104.21.38.247`), serves a real HTTPS site (`HTTP/2 200`, Next.js application headers), and its mail is already routed to Google (`smtp.google.com`), consistent with the existing `academy@rootnodeacademy.com` Google Workspace setup. This is the separate, not-RootNode-owned marketing website (`docs/ WEBSITE_REGISTRATION_AND_CHECKOUT.md`'s explicit boundary) — nothing here was touched, and no DNS record was added or changed. **No subdomain or DNS record exists yet for the Platform API itself** (e.g. `api.rootnodeacademy.com` or similar) — that's the piece blocked on real server hardware. - **Gate 7 — database productionization reviewed**: migrations (37, through Phase 9) verified idempotent again this phase (a fresh `down -v`/`up` cycle and a same-database container restart both apply/re-apply cleanly with zero errors — see `docs/ PHASE10_LAUNCH_READINESS.md`'s regression section). The Ansible `platform` role's `postgres.env.j2`/`.template` already model least-privilege connection strings (`rootnode_platform` app user, not a superuser). No student records of any kind exist to accidentally copy into a production database — this dev/test Postgres only ever holds disposable test fixtures, all cleaned up after each rehearsal. - **Gate 8 — Stripe LIVE**: explicitly **not configured, not attempted**. See "Stripe LIVE status" below. - **Gate 9 — Google Workspace**: `GOOGLE_SERVICE_ACCOUNT_JSON`/`GOOGLE_DELEGATED_USER` already exist as real, previously-validated local values (Phase 5C's own `docs/ RUNBOOK_GOOGLE_WORKSPACE_EMAIL.md` documents that validation) — `academy@rootnodeacademy.com`, `gmail.send` scope only, domain-wide delegation. Not re-sent this phase (no new test email was needed to confirm what Phase 5C already proved, and Phase 10 explicitly says not to make GWS a blocker for Stripe/launch work). Production DEPLOYMENT of this config is blocked on the same missing server as everything else. - **Gates 15/16 — observability and backups reviewed, unchanged**: `/healthz` (Platform API, Gateway, Provisioner) and `/metrics` (Prometheus text exposition, low-cardinality labels only — reconfirmed by this phase's own audit in `docs/PHASE10_SECURITY_AUDIT.md`) already exist and were exercised repeatedly by every regression suite rerun this phase. The `monitoring-agent` and `backup` Ansible roles exist (`infra/ansible/roles/monitoring-agent/`, `.../backup/`, including a templated `run-backup.sh.j2`) — built in Phase 4, never yet run against a real host. **A restore has never been tested against real infrastructure, because none exists** — this phase cannot manufacture that proof; it is not sufficient for launch per Phase 10's own "a backup that has never been restore-tested is not sufficient" rule, and is listed as a real blocker in the launch checklist, not glossed over. ## Stripe LIVE status **Not configured.** No live Stripe credential was provided to this session, and this phase did not request one — activating Stripe live mode requires Chase's own Stripe account business/identity verification (a real KYC-style process only Chase can complete), which is an explicit Phase 10 STOP condition ("identity verification requires Chase"). Phase 9.1's real TEST-mode validation (`docs/PHASE9_1_STRIPE_TEST_VALIDATION.md`) remains the full proof of the application-layer correctness; going live only needs Chase's real credentials plugged into the same, already-proven code path — see `docs/STRIPE_INTEGRATION_RUNBOOK.md`'s "Going live" section, unchanged by this phase. ## Bottom line **PRODUCTION DEPLOYMENT BLOCKED — SERVER REQUIRED.** Every gate that depends on real hardware (4, 5's live verification, 6's platform subdomain, 7's live database, 8, 9's live deployment, 15, 16) is prepared, validated, and ready to execute the moment `rn-platform-01`/`rn-lab-host-01` exist on real Proxmox hardware and `terraform.tfvars`/`group_vars/production.yml` are filled with real values — none of it requires new code or a redesign.