Redirect old Seamtro product paths to app.seamtro.ai (already live in prod) #3

Merged
leora merged 1 commits from seamtro-product-redirects into main 2026-10-17 02:15:26 +00:00
Owner

Adds _redirects, the exact file deployed to Cloudflare Pages production for ni-landing on 17 Oct (deployment ac0de057, built from main 026d17d plus this file), so the repo matches what prod serves.

On 17 Oct the Seamtro product moved from the seamtro.ai apex to https://app.seamtro.ai, and the apex and www now serve this landing page. These rules send the old apex paths to the same path on app.seamtro.ai, query strings kept:

  • 301: /pricing, /privacy, /terms, /affiliate (each with and without a trailing slash), /dashboard and /dashboard/, /form and /form/, /_next/*, /site.webmanifest, /favicon.ico, /favicon-16x16.png, /favicon-32x32.png
  • 308 (keeps the method and body): /api/* to app.seamtro.ai/api/:splat

Known caveat: Stripe does not follow redirects for webhooks, so a webhook pointed at seamtro.ai/api/webhooks/stripe needs updating to app.seamtro.ai in Stripe.

Verified in prod: every listed path returns 301/308 to the matching app.seamtro.ai URL, and app.seamtro.ai serves those pages with 200. Rollback notes are in ops-notes (seamtro-cutover-20261017).

Adds `_redirects`, the exact file deployed to Cloudflare Pages production for ni-landing on 17 Oct (deployment ac0de057, built from main 026d17d plus this file), so the repo matches what prod serves. On 17 Oct the Seamtro product moved from the seamtro.ai apex to https://app.seamtro.ai, and the apex and www now serve this landing page. These rules send the old apex paths to the same path on app.seamtro.ai, query strings kept: - 301: /pricing, /privacy, /terms, /affiliate (each with and without a trailing slash), /dashboard and /dashboard/*, /form and /form/*, /_next/*, /site.webmanifest, /favicon.ico, /favicon-16x16.png, /favicon-32x32.png - 308 (keeps the method and body): /api/* to app.seamtro.ai/api/:splat Known caveat: Stripe does not follow redirects for webhooks, so a webhook pointed at seamtro.ai/api/webhooks/stripe needs updating to app.seamtro.ai in Stripe. Verified in prod: every listed path returns 301/308 to the matching app.seamtro.ai URL, and app.seamtro.ai serves those pages with 200. Rollback notes are in ops-notes (seamtro-cutover-20261017).
leora added 1 commit 2026-10-17 02:12:35 +00:00
leora requested review from code-reviewer 2026-10-17 02:12:42 +00:00
code-reviewer approved these changes 2026-10-17 02:14:44 +00:00
code-reviewer left a comment
First-time contributor

Approved at 156ad4b. The file matches prod.

Live check (read-only HEADs, apex and www): all 18 rules return the stated 301/308 to the same path on app.seamtro.ai, with query strings kept. Every target on app.seamtro.ai returns 200, except /api/webhooks/stripe, which returns 405 to HEAD (expected for a POST-only route).

Syntax and rule order: valid Cloudflare Pages _redirects format (source, absolute target, status).

  • Every rule is a literal path, or a prefix wildcard under /dashboard, /form, /api or /_next. No catch-all.
  • New-site paths are not shadowed: /, /robots.txt, /sitemap.xml and the 404 page are all live; /llms.txt and /.well-known/* from #2 don't overlap any rule.
  • No repo file collides with a source path.

Open redirect: none. Every target is a fixed https://app.seamtro.ai/.... :splat only fills in the path.

  • /dashboard/%2f%2fevil.com goes to app.seamtro.ai/dashboard/%2f%2fevil.com, so the host stays fixed.
  • //evil.com/ returns 404, and /api/..%2f.. returns 400.

308 and POST: 308 (RFC 7538) keeps the method and body for clients that follow redirects. Stripe does not follow redirects for webhooks, so change the Stripe webhook endpoint to https://app.seamtro.ai/api/webhooks/stripe. Other server-to-server POSTers are worth auditing too.

Follow-ups outside this PR (please confirm):

  1. Auth0: /auth/callback has no rule and returns 404 on the apex. app.seamtro.ai serves it (307 when called without a code). Make sure the Auth0 Allowed Callback, Logout and Web Origin URLs list https://app.seamtro.ai/auth/callback, and remove the apex entries once you're done.
  2. App base URL: the callback's error redirect points to https://seamtro.ai/?error=missing_code. That's the landing page now, which suggests the app's base or redirect URL (e.g. AUTH0_BASE_URL / APP_URL) is still the apex. Set it to app.seamtro.ai, or users will land on the landing page after login, logout or errors.
  3. Favicon: the landing declares /logo.png, so redirecting /favicon.ico is harmless. Browsers that probe /favicon.ico anyway will show the Seamtro icon.
  4. /privacy and /terms: they resolve (301 → 200 on app.seamtro.ai). If New Internet needs its own privacy and terms pages later, these rules will have to go.

Privacy grep is clean.

Approved at 156ad4b. The file matches prod. **Live check (read-only HEADs, apex and www):** all 18 rules return the stated 301/308 to the same path on app.seamtro.ai, with query strings kept. Every target on app.seamtro.ai returns 200, except `/api/webhooks/stripe`, which returns 405 to HEAD (expected for a POST-only route). **Syntax and rule order:** valid Cloudflare Pages `_redirects` format (source, absolute target, status). - Every rule is a literal path, or a prefix wildcard under /dashboard, /form, /api or /_next. No catch-all. - New-site paths are not shadowed: `/`, `/robots.txt`, `/sitemap.xml` and the 404 page are all live; `/llms.txt` and `/.well-known/*` from #2 don't overlap any rule. - No repo file collides with a source path. **Open redirect: none.** Every target is a fixed `https://app.seamtro.ai/...`. `:splat` only fills in the path. - `/dashboard/%2f%2fevil.com` goes to `app.seamtro.ai/dashboard/%2f%2fevil.com`, so the host stays fixed. - `//evil.com/` returns 404, and `/api/..%2f..` returns 400. **308 and POST:** 308 (RFC 7538) keeps the method and body for clients that follow redirects. Stripe does not follow redirects for webhooks, so change the Stripe webhook endpoint to `https://app.seamtro.ai/api/webhooks/stripe`. Other server-to-server POSTers are worth auditing too. **Follow-ups outside this PR (please confirm):** 1. **Auth0:** `/auth/callback` has no rule and returns 404 on the apex. app.seamtro.ai serves it (307 when called without a code). Make sure the Auth0 Allowed Callback, Logout and Web Origin URLs list `https://app.seamtro.ai/auth/callback`, and remove the apex entries once you're done. 2. **App base URL:** the callback's error redirect points to `https://seamtro.ai/?error=missing_code`. That's the landing page now, which suggests the app's base or redirect URL (e.g. AUTH0_BASE_URL / APP_URL) is still the apex. Set it to app.seamtro.ai, or users will land on the landing page after login, logout or errors. 3. **Favicon:** the landing declares `/logo.png`, so redirecting `/favicon.ico` is harmless. Browsers that probe `/favicon.ico` anyway will show the Seamtro icon. 4. **/privacy and /terms:** they resolve (301 → 200 on app.seamtro.ai). If New Internet needs its own privacy and terms pages later, these rules will have to go. Privacy grep is clean.
@ -0,0 +11,4 @@
/dashboard/* https://app.seamtro.ai/dashboard/:splat 301
/form https://app.seamtro.ai/form 301
/form/* https://app.seamtro.ai/form/:splat 301
/api/* https://app.seamtro.ai/api/:splat 308
First-time contributor

308 keeps the method and body, but Stripe won't follow it. Point the Stripe webhook endpoint straight at https://app.seamtro.ai/api/webhooks/stripe.

308 keeps the method and body, but Stripe won't follow it. Point the Stripe webhook endpoint straight at https://app.seamtro.ai/api/webhooks/stripe.
leora merged commit de1e93f710 into main 2026-10-17 02:15:26 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: leora/landing#3
No description provided.