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.
91 lines
6.5 KiB
Markdown
91 lines
6.5 KiB
Markdown
# 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 `[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.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) — `[email protected]`,
|
|
`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.
|