Gate 1 — canonical state audit: this workstation's HEAD/origin/main and every claimed milestone SHA (Phase 2A through 9.1) verified consistent; no stranded branches/tags on Gitea; full-history secret scan clean (no rotation required); Phase 9.5 confirmed absent from canonical history (pricing was given directly by Chase and used without it); second-PC reconciliation commands provided since this session cannot see that machine. Gate 3 — secrets: real inventory derived from process.env greps across every service (not guessed); Infisical auth fixed (wrong domain was the actual root cause of Phase 9.1's failures — the identity belongs to infisical.cedshomelab.com, not app.infisical.com) but no RootNode Academy project exists there yet, contradicting this phase's own authorization — flagged for Chase to create. Gates 4-9/15-16 — production: verified, not assumed, that no dedicated server/Proxmox VM has been provisioned (empty terraform.tfvars, no state file, placeholder group_vars/production.yml) — IaC validated (tofu validate, ansible --syntax-check both clean) and left unexecuted per this phase's own 'do not fake production deployment' instruction. rootnodeacademy.com confirmed live (Cloudflare, real HTTPS) — the separate, not-RootNode-owned website; no Platform API subdomain exists yet. Gate 18 — security audit: full review against every regression suite rerun this phase; no launch-critical defect found. Gates 19/20 — full regression (131 checks: e2e-phase5b/5c/6f/7/8/9, content validation, migrations, frontend build) and the Winter Break commerce rehearsal, both rerun clean against current main. Gates 10-14/21 — website integration, Winter Break pricing (99/49, real, Stripe-validated), agreements/legal, tax, and refund policy all reviewed; legal text/tax/refund policy/dates/venue/ capacity correctly left as open owner decisions, not invented. No application code changed this phase — audit/launch-prep only.
6.5 KiB
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 againstinfra/terraform/'s existing Proxmox provider config — no redesign, the existing config is syntactically sound and ready for realterraform.tfvars.ansible-playbook site.yml --syntax-check -i inventorypasses cleanly againstinfra/ ansible/'s existingsite.ymland itsfirewall/docker-tls/platform/lab-host/monitoring-agent/backup/commonroles (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 ininfra/ansible/roles/docker-tls/and referenced bygateway.env.j2; thefirewallAnsible 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.comis 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[email protected]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.comor 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/upcycle and a same-database container restart both apply/re-apply cleanly with zero errors — seedocs/ PHASE10_LAUNCH_READINESS.md's regression section). The Ansibleplatformrole'spostgres.env.j2/.templatealready model least-privilege connection strings (rootnode_platformapp 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_USERalready exist as real, previously-validated local values (Phase 5C's owndocs/ RUNBOOK_GOOGLE_WORKSPACE_EMAIL.mddocuments that validation) —[email protected],gmail.sendscope 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 indocs/PHASE10_SECURITY_AUDIT.md) already exist and were exercised repeatedly by every regression suite rerun this phase. Themonitoring-agentandbackupAnsible roles exist (infra/ansible/roles/monitoring-agent/,.../backup/, including a templatedrun-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.