Skip to content

Route production redesign accounts through Cloudflare - #735

Merged
thomasluizon merged 5 commits into
mainfrom
thomasluizon/ticket-1417-redesign-web-routing
Oct 18, 2026
Merged

thomasluizon merged 5 commits into
mainfrom
thomasluizon/ticket-1417-redesign-web-routing

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Closes thomasluizon/orbit-tickets#1417.

Accounts carrying orbit_design=redesign are routed to a separate production Render web service at the same public address. Other requests retain the current origin and public Host. Removing the Worker route restores the current build for both cookie variants.

infra/production.tf adds the image-backed service using the current production plan, region, health path and production env group, and exports its ID and Render hostname for thomasluizon/orbit-tickets#1499. A required production_redesign_web_digest seeds an approved production-configured redesign/main image; subsequent digest changes are ignored so releases remain manual. infra/cloudflare.tf, infra/web-routing.tf and infra/workers/web-routing.mjs proxy only app DNS and add the cookie router. The redesign request uses its Render Host plus X-Forwarded-Host: app.useorbit.org and X-Forwarded-Proto: https; path, query, method, body and other headers pass through. The current request passes through unchanged.

Miniflare tests cover both routes, exact cookie matching, cookie removal, POST bodies and Server Action headers, callback queries, redirect responses and session cookies. The Terraform workflow installs locked test dependencies and runs all infrastructure tests. The web plan guard now protects the redesign service too. infra/README.md documents rollout, permission checks, live verification and rollback.

Test evidence

  • dotnet build Orbit.slnx: exit 0, zero errors. Generated src/Orbit.Api/openapi.json is unchanged.
  • node --test infra/check-web-plan.test.mjs infra/web-routing.test.mjs: exit 0, 20 passed, including 13 new Worker tests.
  • npm ci --prefix infra and npm test --prefix infra: exit 0, 48 passed. Installation audit reports zero vulnerabilities.
  • dotnet test tests/Orbit.Domain.Tests --no-build: exit 0, 666 passed.
  • dotnet test tests/Orbit.Application.Tests --no-build: exit 0, 5,466 passed.
  • dotnet test tests/Orbit.Infrastructure.Tests --no-build: exit 0, 3,342 passed.
  • terraform fmt -check -recursive infra and terraform -chdir=infra validate -no-color: exit 0.
  • terraform -chdir=infra plan -input=false -no-color: exit 1, Backend initialization required. The S3 backend is not initialized here and Cloudflare/Render credentials are unset. No live plan summary or permission verdict is claimed. No secrets were read and no infrastructure was applied.
  • This adds routing infrastructure; there was no existing Worker routing regression test or shipped routing defect to demonstrate with a before/after test run. Live Next.js, OAuth and edge latency verification requires the orchestrator's apply.

Expected plan scope, pending live confirmation: three creates (redesign service, Worker script, Worker route), app DNS proxy update, and the required production web env-group link update. Existing web services must remain unchanged.

CI round (d5182a1c, SonarCloud quality gate):

  • sonarcloud.yml now installs infra with npm ci --prefix infra --ignore-scripts and writes coverage/web-routing.lcov from infra/web-routing.test.mjs; the routing cases run in Node and in Miniflare, because Miniflare alone produced an empty Node coverage report (TN: only). Local: SF:infra/workers/web-routing.mjs, LF:18, LH:18.
  • terraform.yml:30 runs npm ci --prefix infra --ignore-scripts (S6505).
  • npm ci --prefix infra --ignore-scripts exit 0; npm test --prefix infra exit 0, 61 tests including the workerd cases; actionlint on both workflows exit 0. The test file keeps all 22 assertions.

Base merge (25e67509, b44730e2): main took orbit-api#733 (the v2 document) and orbit-api#734 (the typed /api/config response) in parallel, so main's committed openapi_v2.json lacked the AppConfigResponse schema and the Build check's stale-document step failed on this pull request's merge commit. dotnet build src/Orbit.Api (exit 0) regenerates it; openapi.json is unchanged. Merging this pull request clears that red on main.

Interface evidence

The live pinned Cloudflare script schema, route schema, and DNS schema confirm the used resources, bindings and proxy fields. Routes require proxied DNS; the Request contract confirms request cloning and header rewriting. Render image deployments do not automatically redeploy images.

A real terraform providers schema -json invocation with the installed pinned providers in a backend-disabled scratch root confirmed render_web_service.id and .url: each is { "type": "string", "computed": true }, with descriptions identifying the service ID and accessible URL. The complete image attribute-name set is digest, image_url, registry_credential_id, tag; there is no image auto_deploy field. Reproduce using the provider declarations from infra/versions.tf without its S3 backend, then initialize and run the schema command. No new Render HTTP response fields are consumed.

The live Miniflare testing docs confirm the testing API. Installed miniflare/dist/src/index.d.ts and dist/src/index.js confirm outboundService receives a real Request and returns a Response, bindings supplies environment values, and dispatchFetch invokes the module. Tests assert the actual runtime-generated outbound requests rather than inventing external response fixtures.

Assumptions

  • Require an explicit production_redesign_web_digest from a published production-configured redesign image, rather than bootstrapping the new service with the current build's digest.
  • Use Node's existing infrastructure test runner with Miniflare rather than introducing a separate Vitest runner; pin the Worker compatibility date to one the installed runtime supports.

Manual steps

  • Cloudflare > My Profile > API Tokens: verify the token supplying CLOUDFLARE_API_TOKEN has account-level Workers Scripts Write and zone-level Workers Routes Write and DNS Write. The provider also lists Workers Scripts Read, Workers Routes Read and DNS Read for reads. Existing script access does not prove route access. Token inspection is unverified here; report an actual denial with its exact permission name.
  • Existing Terraform execution environment > ignored infra/local.tfvars: supply production_redesign_web_digest for the approved production redesign/main image, retain dns_app_target = "orbit-web-3qmv.onrender.com" and web_custom_domains = ["app.useorbit.org"], then review a saved plan and the web plan guard output before applying through the existing infrastructure process. The plan must have only the scope above.
  • Render > orbit-web-redesign > Environment and Settings > Deploy: confirm orbit-production-web, NEXT_PUBLIC_SITE_URL=https://app.useorbit.org, the approved image digest, and service health. Read outputs production_redesign_web_service_id and production_redesign_web_host for #1499. That UI ticket owns its repository variable key and production branch/service selection in GitHub Actions > release.yml; this PR does not modify the UI repository.
  • Public app after the UI cookie change and #1499 are deployed: compare /api/health with and without orbit_design=redesign to the approved redesign/main and main commits, then remove the cookie and reload. Verify Google and email sign-in, /auth-callback, every configured callback, session renewal, and Server Actions on both routes with the browser staying on app.useorbit.org.
  • Cloudflare deployment verification: measure cached immutable-asset and uncached /api/health added latency using interleaved routed and direct-origin requests from the same location, preserving public TLS/Host, confirming cache status and recording sample count and median TTFB deltas. Cached added latency: not measured before apply. Uncached added latency: not measured before apply.
  • Rollback check in Cloudflare > Workers & Pages > orbit-web-routing > Settings > Domains & Routes: deleting only app.useorbit.org/* must return both cookie variants to the current health commit. Preserve the DNS target and current service custom domain; remove the route from Terraform before an apply intended to retain rollback.

pullfrog[bot]
pullfrog Bot previously approved these changes Oct 17, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the production routing infrastructure, Worker behavior, runtime tests, and paired web changes across both repositories.

  • Production origin: Adds a separately pinned redesign Render service, shared production configuration, release outputs, and plan-guard protection.
  • Cookie routing: Proxies the app hostname through Cloudflare, routes the exact redesign cookie to its own origin, and preserves request bodies, callbacks, redirects, and session cookies.
  • Rollout and rollback: Documents approved-image bootstrap, permissions, live verification, and restoration of the current origin by removing the Worker route. Canonical-host compatibility is addressed by paired orbit-ui-mobile#1832; the initial redesign image depends on that fix. Manual releases are covered by orbit-ui-mobile#1829.
  • Verification: Independently ran the infrastructure suite: all 48 tests passed. Terraform was unavailable locally (terraform: command not found); the PR's Terraform validation check passed. Live OAuth, session, and latency verification remain deployment-time checks.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

pullfrog[bot]
pullfrog Bot previously approved these changes Oct 18, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the CI and routing-test changes since dccbf368; production Worker behavior and Terraform resources are unchanged.

  • Added Worker coverage: Included web-routing.lcov in SonarCloud and installed the locked infrastructure dependencies before coverage generation.
  • Preserved runtime verification: Ran the routing cases in both Node and workerd, allowing Node coverage collection without replacing Cloudflare runtime checks.
  • Disabled install scripts: Updated both CI workflows to use npm ci --prefix infra --ignore-scripts.
  • Verified the delta: Independently installed dependencies with scripts disabled and passed all 61 infrastructure tests. The generated Worker LCOV report covered all 18 lines and all 6 branches. Live OAuth, session, and latency verification remain deployment-time checks.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

thomasluizon and others added 2 commits October 17, 2026 22:01
orbit-api#733 added openapi_v2.json and orbit-api#734 typed the /api/config
response in parallel, so main carries a v2 document without the typed config
schema and the Build check's stale-document step fails on every merge with
main. dotnet build src/Orbit.Api regenerates it; openapi.json is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the delta since d5182a1: the merge from main and regenerated v2 OpenAPI config documentation; routing behavior and infrastructure are unchanged.

  • Regenerated config documentation: Added the existing config response and its three schemas to openapi_v2.json, matching ConfigController and the committed v1 document without changing runtime payloads.
  • Verified schema consistency: Independently checked equality of the config response and schemas across v1/v2, resolved all 1,593 local v2 references, and inspected the sibling consumer types. No full build or unit suite was rerun for this generated-document-only delta.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@sonarqubecloud

Copy link
Copy Markdown

@thomasluizon
thomasluizon merged commit 9c64770 into main Oct 18, 2026
29 checks passed
@thomasluizon
thomasluizon deleted the thomasluizon/ticket-1417-redesign-web-routing branch October 18, 2026 02:09
thomasluizon added a commit that referenced this pull request Oct 18, 2026
* fix: pin analyzer test Pkcs dependency to patched version (#728)

(cherry picked from commit 61b0090)

* fix: shard pull request domain mutation testing (#729)

(cherry picked from commit bcfd81e)

* Promote the API redesign with production compatibility checks (#723)

* Bring the API redesign tree onto main for #1413

* Preserve calendar connection detection for shipped clients

* Prove API and migrated schema compatibility with shipped clients

* Trim whitespace in the archived main schema proof

* Require the production health response to report the released commit

* Bind initial approval previews to stored pending operations

* fix: return the bulk skip refresh outcome and split the undo skip query

SonarCloud failed the quality gate on two reliability findings in code this pull request brings to main:
the bulk skip conflict check read a flag only a lambda wrote (S2583), and the undo skip check loaded
Tags and Goals in one query (S8733). The transaction now returns whether every habit refreshed, and the
undo skip check splits its query. A new case covers the concurrent change conflict; it failed with the
refresh outcome forced to true and passes with the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5526c9b)

* Add per-account feature flag targeting and admin controls (#724)

* feat: resolve feature flags per account

* feat: administer account feature flags through MCP and REST

* test: exclude feature flag targets from rate limit fixture

* fix: reconcile account flag tests and migration metadata with redesign

(cherry picked from commit 1b886bd)

* Add header API versioning for v1 and v2 (#733)

* Add header API versioning with v1 compatibility

* Verify versioned OpenAPI and browser header compatibility

* Preserve skip undo path contract with optional version header

(cherry picked from commit ac8b34a)

* fix: expose the config response in OpenAPI (#734)

(cherry picked from commit a9d8dd5)

* Route production redesign accounts through Cloudflare (#735)

* Add cookie-based routing for the production redesign web service

* Document web routing rollout, permissions, and rollback checks

* Fix web routing coverage and disable infra install scripts

* chore: regenerate the v2 OpenAPI document on main

orbit-api#733 added openapi_v2.json and orbit-api#734 typed the /api/config
response in parallel, so main carries a v2 document without the typed config
schema and the Build check's stale-document step fails on every merge with
main. dotnet build src/Orbit.Api regenerates it; openapi.json is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9c64770)

* Fix habit edit gating, end dates, and reminder updates (#736)

* fix: validate habit updates with the resulting time range

* fix: preserve end dates when creating root habits

* fix: gate slip alert activation and preserve unchanged reminders

* fix: compare effective reminder rules across stored formats

(cherry picked from commit 7472203)

* Reduce mutation and guard CI jobs (#737)

* Select mutation shards from changed projects

* Consolidate guards and filter artifact generation

* Skip project documentation in mutation selection

* Validate mutation base refs and restrict Git PATH

* Read mutation shard changes from standard input

(cherry picked from commit b802f9e)

* test: strengthen habit and goal ownership coverage (#739)

(cherry picked from commit 0e32628)

* test: verify checkout session user metadata (#740)

(cherry picked from commit da2f53a)

* fix: protect OAuth code delivery with Turnstile (#741)

(cherry picked from commit 1149606)

* fix: enforce chat interaction scope before loading context (#743)

(cherry picked from commit 98faf4e)

* fix: erase accountability pairs during account deletion and reset (#745)

* fix: erase accountability pairs during account deletion and reset

* test: preserve migration compatibility checks after accountability cleanup

(cherry picked from commit a9e5fb9)

* Fix goal sync dates and deadline reminder counts (#747)

* fix: compare streak sync dates in the user timezone

* fix: show actual days remaining in goal deadline reminders

* test: configure timezone for streak scheduler fixtures

(cherry picked from commit 0e63842)

* Manage staging landing routing in Terraform (#742)

(cherry picked from commit abdd738)

* Restrict Web Push endpoints to supported push services (#1503) (#751)

Web Push subscriptions accept only HTTPS endpoints on the FCM, Mozilla, Apple and WNS push hosts, and the push HTTP client follows no redirects. Replaces orbit-api#748 as one commit so no commit carries the high-entropy sample fixture.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d9f847a)

* Erase account uploads before permanent deletion (#1507) (#750)

* fix: erase uploaded objects before completing account deletion

* fix: refuse upload reads after permanent account deletion

* fix: grant uploads bucket deletion permissions and verify provider wiring

* test: align storage startup checks with erasure requirements

* fix: retire deleted Supabase upload storage

* test: configure upload erasure providers in deletion fixtures

Share the existing object-store fake across account deletion and scheduler fixtures after merging main. Preserve accountability assertions and production provider requirements for thomasluizon/orbit-tickets#1507.

(cherry picked from commit fa33a94)

* fix: limit anonymous auth and waitlist by email and source IP (ORB-108) (#749)

* fix: enforce source IP ceilings alongside anonymous email limits

* test: cover both rate limit dimensions before bot verification

* fix: isolate BFF email rate limits by verified client IP

* fix: generate and persist BFF forwarding secrets

(cherry picked from commit de0f42f)

* Limit access tokens to fifteen minutes (#738)

* fix(auth): limit access tokens to fifteen minutes

* fix(auth): align managed JWT lifetime and prove logout rejection

(cherry picked from commit ade7016)

* fix(auth): equalize account provisioning work (ORB-96) (#744)

* test(auth): expose registration dependent sign-in work

* fix(auth): perform uniform registration work before sign-in responses

* test(auth): cover expired codes and tracked upsert conflicts

* fix(auth): isolate signup retries and restore provisioning guards

* fix(auth): recover signup work after dispatch failures

* fix(auth): roll back failed signup referrals before retry

(cherry picked from commit 1bd0d26)

* fix: expose redesign controllers in both API versions

Apply the carried version declarations to the Notion and proactive controllers and regenerate the v2 contract. Refs thomasluizon/orbit-tickets#746.

* fix: honor account flags in proactive engine

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant