Release 0.3.0: private-beta gate + anonymous read mode

Adds an email allowlist (toggleable per deployment) that restricts
OAuth sign-in to listed emails while keeping read paths public.
Anonymous visitors now see the full app shell in read-only mode
instead of the §14.1 landing wall. Empty allowlist = gate off, so
deployments that don't enable it behave exactly as 0.2.3.

Also fixes single-finger scroll on /philosophy and other .chrome-pane
views on iOS Safari (.app: 100vh → 100dvh).

Renames deploy/nginx/rfc.wiggleverse.org.conf →
ohm.wiggleverse.org.conf to match the deployed-domain rename
(rfc.wiggleverse.org deprovisioned 2026-05-27).

See CHANGELOG.md for full details + upgrade steps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-05-27 20:58:58 -07:00
parent 1a9374aa52
commit 21fcbc92d4
19 changed files with 715 additions and 87 deletions
+31 -2
View File
@@ -69,7 +69,7 @@ The shortest path from scratch:
any deployment-identifying value; if a required variable is
missing, the build fails loudly.
6. **Build and run.** `cd frontend && npm install && npm run
6. **Build and run.** `cd frontend && npm ci && npm run
build`, then start the backend per `deploy/RUNBOOK.md`. The
first sign-in is the OWNER login from `backend/.env`.
@@ -166,7 +166,7 @@ The mechanics in practice:
5. **Check out the framework at the target version.** `git
fetch && git checkout <tag>`.
6. **Rebuild.** `npm install && npm run build` for the frontend;
6. **Rebuild.** `npm ci && npm run build` for the frontend;
restart the backend.
7. **Smoke-test.** Sign in, check the brand reflects your
@@ -240,6 +240,35 @@ The deployment repo does **not** hold:
edit a framework file, the right move is to file a change against
the framework, get a release, and pin to it.
## Private-beta gate
From `0.3.0` onward, every deployment ships with an opt-in email
allowlist. The default state is **off**: an empty `allowed_emails`
table behaves exactly like 0.2.x — any successful Gitea OAuth
provisions a user.
To run a closed beta:
1. Sign in once as the deployment operator so your `users` row exists
(you will be grandfathered by `gitea_id` thereafter — adding the
first allowlist row does **not** lock you out).
2. Open `/admin/allowlist` and add the first invited email. As soon as
any row exists, sign-in is restricted to listed emails plus
grandfathered users.
3. Optionally set `VITE_BETA_CONTACT` in `frontend/.env` (an email
address, a URL, or a short instruction). It is shown to rejected
sign-ins on the `/beta-pending` page so visitors know how to
request an invitation.
To re-open the deployment, remove all rows from `allowed_emails` (the
admin tab has a Remove button per row) — the gate flips off as soon
as the last row is gone.
Anonymous viewers see the full app in read-only mode regardless of
allowlist state. Write affordances (Propose, chat, Contribute, Open
PR) are hidden behind a sign-in CTA, and the public read endpoints
behave the same in both states.
## When something goes wrong
If a framework behavior is wrong for your deployment, file it as a