Add website same-origin deployment handoff

This commit is contained in:
axiomlogicnexus 2026-06-22 06:50:15 +00:00
parent f160b7eb4c
commit 8a38ecdecc
10 changed files with 326 additions and 1 deletions

View file

@ -184,6 +184,9 @@ for `hypertwist.app` when a built `website/dist/index.html` is present:
- the runtime-readiness verifier now warns when same-origin public posture leaves that static-serving mode implicit
- request-level server coverage now also proves the live route behavior for public/app routes versus `/api/*`, `/auth*`, `/health`, and missing asset paths
- the frontend public deployment surface now also includes first-party `robots.txt` plus `sitemap.xml` assets for the current public route set, while keeping `/app`, `/login`, and `/register` out of crawler posture
- the repo now also includes first-party `website/deploy/` handoff templates
for `nginx` plus `systemd`, with the concrete operator cutover sequence
recorded in `docs/ops/HYPERTWIST_WEBSITE_SAME_ORIGIN_DEPLOYMENT_HANDOFF_2026-06-22.md`
This is browser-based user access for the operator/account surface.

View file

@ -86,6 +86,8 @@ when a built website bundle exists:
- set `SERVE_STATIC_WEBSITE=false` to keep api-only mode explicit
- set `SERVE_STATIC_WEBSITE=true` to require bundle presence instead of silently staying api-only
- the readiness verifier now warns when same-origin public posture leaves this static-serving mode ambiguous
- the repo now also carries first-party `systemd` and `nginx` handoff templates
under `website/deploy/` plus a same-origin deployment cutover guide
## If a split-host auth topology is chosen later
@ -142,7 +144,9 @@ auth-server ownership in the repo.
- `website/README.md`
- `website/server/README.md`
- `website/deploy/README.md`
- `docs/ops/HYPERTWIST_PUBLIC_WEBSITE_AUTH_BILLING_AND_DISTRIBUTION_PACKET_2026-06-22.md`
- `docs/ops/HYPERTWIST_WEBSITE_SAME_ORIGIN_DEPLOYMENT_HANDOFF_2026-06-22.md`
- `docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md`
- `docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md`
- `docs/ops/HYPERTWIST_VPS_TLS_CERTIFICATE_AND_IONOS_SEPARATION_GUIDE_2026-05-30.md`

View file

@ -0,0 +1,205 @@
# HyperTwist Website Same-Origin Deployment Handoff
Created on `2026-06-22`.
## Purpose
This note records the concrete cutover path for replacing the current
placeholder `hypertwist.app` page with the first-party HyperTwist website plus
auth-server lane already shipped in the repo.
This is the next operator step after:
- the public website implementation packet
- the server-backed release-manifest authority packet
- the runtime-readiness placeholder-detection hardening
## Current live problem on `2026-06-22`
The public origin is still serving the older placeholder rollout page:
- `https://hypertwist.app/`
- `https://hypertwist.app/api/auth/health`
- `https://hypertwist.app/api/releases/manifest`
All three currently return the placeholder HTML page instead of the real
same-origin website/auth-server deployment.
## Intended production topology
The simplest honest deployment is:
1. build the frontend in `website/`
2. run `website/server` as the long-lived local process on the VPS
3. let the server auto-serve `../dist`
4. put NGINX in front of that process on `https://hypertwist.app`
That gives one public origin for:
- the marketing shell
- auth routes
- dashboard routes
- `GET /api/auth/health`
- `GET /api/releases/manifest`
- `POST /api/billing/paddle/webhook`
## Repo-provided deployment templates
The repo now includes first-party same-origin templates under:
- `website/deploy/nginx/hypertwist.app.conf.example`
- `website/deploy/systemd/hypertwist-website-auth-server.service.example`
- `website/deploy/README.md`
These are operator handoff templates, not automatically applied machine state.
## Expected filesystem posture on the VPS
Example working checkout:
- repo root: `/srv/hypertwist/current`
- frontend: `/srv/hypertwist/current/website`
- server: `/srv/hypertwist/current/website/server`
Expected build output:
- `/srv/hypertwist/current/website/dist/index.html`
Expected runtime env files:
- `/srv/hypertwist/current/website/.env`
- `/srv/hypertwist/current/website/server/.env`
## Cutover sequence
### 1. Sync the current repo to the VPS
Ensure the current `main` branch includes:
- `f160b7e` `Harden live website deployment readiness probe`
- the earlier website/auth/distribution commits on `2026-06-22`
### 2. Fill real production env values
Start from:
- `website/.env.production.example`
- `website/server/.env.production.example`
Replace placeholders with real production values before launch.
Minimum required live values include:
- `VITE_SUPERTOKENS_API_DOMAIN=https://hypertwist.app`
- `VITE_SUPERTOKENS_WEBSITE_DOMAIN=https://hypertwist.app`
- `VITE_AUTH_API_BASE_URL=https://hypertwist.app`
- real operator checkout URL
- real Windows download URL
- real corresponding-source URL
- `API_DOMAIN=https://hypertwist.app`
- `WEBSITE_DOMAIN=https://hypertwist.app`
- `COOKIE_SECURE=true`
- real `PADDLE_WEBHOOK_SECRET`
- real billing product/price map
- real release-manifest metadata values
### 3. Install dependencies and build the frontend
```bash
cd /srv/hypertwist/current/website
npm ci
npm run build
cd /srv/hypertwist/current/website/server
npm ci
```
### 4. Install the systemd service
Use:
- `website/deploy/systemd/hypertwist-website-auth-server.service.example`
Before enabling it:
- replace `User=` and `Group=` if the service does not run as `hypertwist`
- replace `WorkingDirectory=` with the real checkout path
- replace `EnvironmentFile=` with the real server env path
Install sequence:
```bash
sudo cp /srv/hypertwist/current/website/deploy/systemd/hypertwist-website-auth-server.service.example \
/etc/systemd/system/hypertwist-website-auth-server.service
sudo systemctl daemon-reload
sudo systemctl enable --now hypertwist-website-auth-server.service
sudo systemctl status hypertwist-website-auth-server.service --no-pager
```
### 5. Install the NGINX vhost
Use:
- `website/deploy/nginx/hypertwist.app.conf.example`
Install sequence:
```bash
sudo cp /srv/hypertwist/current/website/deploy/nginx/hypertwist.app.conf.example \
/etc/nginx/sites-available/hypertwist.app
sudo ln -s /etc/nginx/sites-available/hypertwist.app /etc/nginx/sites-enabled/hypertwist.app
sudo nginx -t
sudo systemctl reload nginx
```
This config expects the existing Certbot-managed certificate paths already
described in:
- `docs/ops/HYPERTWIST_VPS_TLS_CERTIFICATE_AND_IONOS_SEPARATION_GUIDE_2026-05-30.md`
### 6. Confirm the placeholder page is gone
The current public-origin proof should flip from placeholder HTML to real
website/auth-server behavior:
```bash
curl --silent --show-error https://hypertwist.app/api/auth/health
curl --silent --show-error https://hypertwist.app/api/releases/manifest
curl --silent --show-error https://hypertwist.app/ | rg "hypertwist-site-shell|id=\"root\""
```
### 7. Run the first-party readiness verifier
From the live checkout:
```bash
cd /srv/hypertwist/current/website
npm run check:runtime-readiness -- --frontend-env .env --server-env server/.env --health-url https://hypertwist.app
```
Expected live success conditions:
- `/api/auth/health` returns JSON and reports public-ready posture
- `/api/releases/manifest` returns JSON and keeps anonymous download URLs hidden
- `/` exposes the first-party shell marker and `#root` mount
- no placeholder rollout page text remains
## Fast rollback logic
If cutover breaks:
1. inspect `journalctl -u hypertwist-website-auth-server.service -n 200 --no-pager`
2. inspect `sudo nginx -t`
3. confirm `website/dist/index.html` exists
4. confirm `website/server/.env` has no placeholder values left
5. if necessary, disable the site vhost and restore the prior placeholder-only
NGINX config while keeping the repo state intact for reattempt
## Authority links
- `website/README.md`
- `website/server/README.md`
- `docs/ops/HYPERTWIST_WEBSITE_RUNTIME_CONFIGURATION_GUIDE_2026-06-22.md`
- `docs/ops/HYPERTWIST_PUBLIC_WEBSITE_AUTH_BILLING_AND_DISTRIBUTION_PACKET_2026-06-22.md`

View file

@ -263,7 +263,7 @@ repo.
| Feature | Status | Primary authority | Notes |
|---|---|---|---|
| Public `hypertwist.app` marketing shell | Implemented now | first-party `website/` app + feature registry/roadmap authority | HyperTwist now has a dedicated first-party public web surface for homepage, about, resources, pricing, download, support, and legal routes. This lane is separate from the embedded Unreal browser runtime under `Content/Browser/` and does not claim browser-simulator parity. The same package now also carries a first-party external runtime-readiness verifier so deploy-time env and live health posture can be checked outside the dashboard, plus separated local-versus-production env templates whose placeholder values are intentionally rejected until real launch config is in place, bootstrap CI now validates both the frontend and auth-server website commands directly, and the auth server can now auto-serve the built `website/dist` bundle with bounded SPA fallback for same-origin public deployment. Request-level server coverage now also proves that public/app shell delivery does not shadow `/api/*`, `/auth*`, `/health`, or missing asset paths, while the pricing/download/notices routes now surface first-party preview-versus-launch posture from the same bounded launch checklist instead of relying on hidden operator-only status. The live website lane now also owns route-aware title/description/canonical/Open-Graph/Twitter metadata for the real `hypertwist.app` marketing surface so deployed public pages no longer remain on a single generic SPA title/description, plus first-party `robots.txt` and `sitemap.xml` assets for the public route set while keeping `/app`, `/login`, and `/register` out of crawler posture. The real `check-runtime-readiness` CLI is now also exercised against the checked-in production example env files, and a spawned `website/server` bootstrap proof now verifies the live same-origin process path from production-shaped env into `/health`, `/api/auth/health`, built-shell serving, and the public anonymous release-manifest posture for the shared desktop release lane. The same verifier now also probes the deployed root-shell marker and can explicitly fail when the public origin is still serving the older placeholder rollout page instead of the first-party website/auth-server lane. |
| Public `hypertwist.app` marketing shell | Implemented now | first-party `website/` app + feature registry/roadmap authority | HyperTwist now has a dedicated first-party public web surface for homepage, about, resources, pricing, download, support, and legal routes. This lane is separate from the embedded Unreal browser runtime under `Content/Browser/` and does not claim browser-simulator parity. The same package now also carries a first-party external runtime-readiness verifier so deploy-time env and live health posture can be checked outside the dashboard, plus separated local-versus-production env templates whose placeholder values are intentionally rejected until real launch config is in place, bootstrap CI now validates both the frontend and auth-server website commands directly, and the auth server can now auto-serve the built `website/dist` bundle with bounded SPA fallback for same-origin public deployment. Request-level server coverage now also proves that public/app shell delivery does not shadow `/api/*`, `/auth*`, `/health`, or missing asset paths, while the pricing/download/notices routes now surface first-party preview-versus-launch posture from the same bounded launch checklist instead of relying on hidden operator-only status. The live website lane now also owns route-aware title/description/canonical/Open-Graph/Twitter metadata for the real `hypertwist.app` marketing surface so deployed public pages no longer remain on a single generic SPA title/description, plus first-party `robots.txt` and `sitemap.xml` assets for the public route set while keeping `/app`, `/login`, and `/register` out of crawler posture. The real `check-runtime-readiness` CLI is now also exercised against the checked-in production example env files, and a spawned `website/server` bootstrap proof now verifies the live same-origin process path from production-shaped env into `/health`, `/api/auth/health`, built-shell serving, and the public anonymous release-manifest posture for the shared desktop release lane. The same verifier now also probes the deployed root-shell marker and can explicitly fail when the public origin is still serving the older placeholder rollout page instead of the first-party website/auth-server lane, while the repo now also carries first-party `website/deploy/` `nginx` plus `systemd` handoff templates and a concrete same-origin public-host cutover guide. |
| Browser-based operator/account dashboard | Implemented now | first-party `website/` app + shared auth/dashboard packet | A protected browser dashboard is now live for operator access, account state, download posture, browser-access boundary explanation, notices review, and bounded billing/entitlement status. It reuses the shared SuperTokens auth posture proven in FamiliarOS and ScriptoriumAI while remaining HyperTwist-specific in product content and boundary claims, the current auth-health surface now truthfully distinguishes configured versus reachable or ready shared-core posture while exposing fallback-active reason instead of hardcoding readiness, and the same dashboard now also surfaces launch-readiness truth for download URLs, checkout links, source/notices URLs, billing-secret/map configuration, and local-versus-public runtime deployment posture. Focused frontend coverage now also protects deep-link login redirect preservation, safe `next`-path normalization across auth entry points, fallback/email auth-bootstrap normalization, login/register continuation behavior, public download-gating behavior, protected-route/shell behavior, real lazy-route tree behavior for key public and protected paths, top-level app-bootstrap and SuperTokens-wrapper posture, login/register unhappy-path and OAuth-button behavior, support-topic fallback routing when live checkout is not configured, desktop-link verify-url/dashboard readiness behavior, and explicit `noindex,nofollow` posture on protected/auth browser surfaces. The validation lane now also has a bounded signed test-session harness under `TEST_MODE=testing` that proves `/api/auth/me` and `/api/auth/desktop-link` behavior through the live spawned auth-server process without widening production auth posture. |
| Desktop download posture and browser-to-desktop pairing | Implemented now | first-party `website/` app + `website/server` desktop-link endpoints | Public download targets, dashboard-side release posture, and short-lived desktop-link token generation/verification are now first-party owned. The current server posture now enforces exact website-origin matching, bounded per-user issuance, one-time token consumption, and billing-backed plan/download entitlement resolution with focused `website/server` tests green on `2026-06-22`, and the verify handshake now returns the same resolved download-entitlement posture the dashboard sees instead of only identity plus plan/role. The same lane now also owns a shared `GET /api/releases/manifest` runtime authority for release version/channel/build/published/file-size/checksum/docs/source metadata, with anonymous callers intentionally denied raw download URLs while entitled session-backed callers receive the configured direct platform URL. The public `/download` page now keeps raw download URLs behind the protected dashboard instead of exposing them directly, preserves requested platform continuity through `/app/downloads?platform=...`, and surfaces that requested target again after auth handoff inside the protected release lane. Both the public and protected download surfaces now also carry first-party rollout steps plus release/notices/source references so the desktop setup lane is more than a generic link bucket, and the dashboard plus public launch-status callouts now consume the same manifest-backed Windows download truth instead of only static frontend config. Actual release URLs remain deployment configuration rather than hardcoded product truth. |
| Paddle-ready pricing and billing webhook seam | Implemented now | first-party `website/` app + `website/server` billing endpoint | The public pricing surface now exists with plan structure, checkout-link configuration seams, and the same `/api/billing/paddle/webhook` endpoint family used by the broader product website lane. The current server now verifies `Paddle-Signature` against `PADDLE_WEBHOOK_SECRET` using the documented raw-body HMAC flow, persists a bounded first-party billing state file, and applies verified Paddle events into account/download entitlement state that the browser dashboard consumes, with focused `website/server` tests green on `2026-06-22`. A spawned live-process proof now also verifies that a real signed webhook updates processed-event health and persisted billing state through the actual auth-server runtime, not only helper-level store tests, and transaction events no longer leak their id into stored `subscriptionId` state. Production checkout URLs, secret management, and broader operator/admin billing workflows remain deployment/application tasks, not shipped-code omissions. |

View file

@ -258,6 +258,11 @@ Current consolidated milestone snapshot:
instead of leaving it implicit, and request-level server coverage now proves
that public/app routes stay served without shadowing `/api/*`, `/auth*`, or
`/health`,
and the repo now also carries first-party same-origin `nginx` plus `systemd`
handoff templates under `website/deploy/` with a concrete public-host cutover
guide in
`C:\HyperTwist\docs\ops\HYPERTWIST_WEBSITE_SAME_ORIGIN_DEPLOYMENT_HANDOFF_2026-06-22.md`
so the remaining live-host gap is no longer an undocumented operator step,
and the live public website lane now also owns route-aware
title/description/canonical/Open-Graph/Twitter metadata for the real
`hypertwist.app` marketing surface while marking protected/auth routes as

View file

@ -102,6 +102,7 @@ Relevant server env keys now include:
- frontend app: `website/src/`
- auth server: `website/server/`
- deployment templates: `website/deploy/`
- embedded Unreal browser runtime: `Content/Browser/`
- HyperTwist feature authority: `docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md`
- HyperTwist roadmap authority: `docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md`
@ -131,6 +132,8 @@ Use the runtime-readiness command before public launch or deployment approval:
- it now fails explicitly when the live origin is still serving the placeholder
rollout page instead of the first-party website/auth-server lane
- the auth server can now also serve the built `website/dist` bundle directly for same-origin `hypertwist.app` deployment when that build output is present
- the repo now also includes first-party same-origin `nginx` and `systemd`
handoff templates under `website/deploy/`
- it now warns when same-origin public deployment leaves static website serving mode ambiguous
- request-level server tests now also pin that same-origin shell behavior instead of relying only on helper-level assertions
- the public pricing/download/notices pages now also surface preview-versus-launch posture directly from the same bounded launch checklist
@ -156,3 +159,7 @@ The focused frontend test coverage now also pins:
- dashboard launch-readiness plus desktop-link verify-url behavior
- route-aware metadata behavior for public versus protected surfaces plus richer download-lane guidance on both the public and protected release pages
- spawned `website/server` bootstrap proof from production-shaped same-origin env into live `/health`, `/api/auth/health`, static public/app shell delivery, verified webhook reflection into billing state, and bounded session-backed `/api/auth/me` plus `/api/auth/desktop-link` behavior under `TEST_MODE=testing`
Canonical same-origin cutover guide:
- `docs/ops/HYPERTWIST_WEBSITE_SAME_ORIGIN_DEPLOYMENT_HANDOFF_2026-06-22.md`

29
website/deploy/README.md Normal file
View file

@ -0,0 +1,29 @@
# HyperTwist Website Deployment Templates
This folder contains first-party same-origin deployment templates for the
public `hypertwist.app` website plus auth-server lane.
Files:
- `nginx/hypertwist.app.conf.example`
- `systemd/hypertwist-website-auth-server.service.example`
Expected deployment posture:
- NGINX terminates TLS for `hypertwist.app`
- NGINX reverse-proxies the full public origin to the local
`website/server` Express process
- the Express process serves both the built `website/dist` bundle and the
`/api/*` plus `/auth*` route families on the same origin
Before using these templates:
- replace filesystem paths to match the real VPS checkout location
- replace service-user/group values if the process does not run as
`hypertwist`
- fill real production values into `website/.env` and `website/server/.env`
- build the frontend bundle with `npm run build` in `website/`
Canonical operator guide:
- `docs/ops/HYPERTWIST_WEBSITE_SAME_ORIGIN_DEPLOYMENT_HANDOFF_2026-06-22.md`

View file

@ -0,0 +1,45 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream hypertwist_website_auth_server {
server 127.0.0.1:3001;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name hypertwist.app www.hypertwist.app;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name hypertwist.app www.hypertwist.app;
ssl_certificate /etc/letsencrypt/live/hypertwist.app/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hypertwist.app/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
client_max_body_size 10m;
location / {
proxy_pass http://hypertwist_website_auth_server;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
}

View file

@ -0,0 +1,22 @@
[Unit]
Description=HyperTwist same-origin website and auth server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=hypertwist
Group=hypertwist
WorkingDirectory=/srv/hypertwist/current/website/server
Environment=NODE_ENV=production
EnvironmentFile=/srv/hypertwist/current/website/server/.env
ExecStart=/usr/bin/npm start
Restart=always
RestartSec=5
TimeoutStopSec=20
KillSignal=SIGTERM
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

View file

@ -86,6 +86,7 @@ The server now also supports a bounded first-party same-origin deployment mode:
- request-level tests now also prove that public/app routes serve the shell while `/api/*`, `/auth*`, `/health`, and missing asset paths remain unshadowed
- a spawned bootstrap test now also proves the real `src/index.ts` process can start from production-shaped same-origin env, reach a ready SuperTokens core, expose green `/api/auth/health`, serve the built shell, accept a verified webhook, and reflect that processed billing event through live health plus the persisted entitlement file
- the same spawned proof lane now also exercises `/api/auth/me` and `/api/auth/desktop-link` through a bounded signed test-session harness that is only active when `TEST_MODE=testing` and `HYPERTWIST_TEST_SESSION_SECRET` are explicitly set; this is validation-only, not a production auth widening
- the repo now also ships first-party `systemd` plus `nginx` handoff templates under `website/deploy/` for that same-origin public lane
The website package now also ships a deploy-time verification command:
@ -149,6 +150,10 @@ That means the verifier can now fail explicitly when `hypertwist.app` is still
serving the earlier placeholder rollout page instead of the real same-origin
website/auth-server deployment.
Canonical deployment handoff:
- `docs/ops/HYPERTWIST_WEBSITE_SAME_ORIGIN_DEPLOYMENT_HANDOFF_2026-06-22.md`
The repo bootstrap CI now also validates this auth-server lane through:
- `npm ci`