From 25efc382362b1b2f959a1a04dcedd7790ac1f684 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 27 Oct 2026 11:59:45 +0000 Subject: [PATCH] Move to debateowl.com and 301 the old domain --- .../verify-debatelab/features/localization.md | 2 +- AGENTS.md | 2 +- README.md | 2 +- docs/operations.md | 6 +- docs/testing.md | 2 +- e2e/free-tools.spec.ts | 2 +- e2e/loading-performance.spec.ts | 6 +- e2e/localization.spec.ts | 2 +- embed/debate-timer/index.html | 4 +- index.html | 14 +-- playwright.production.config.ts | 2 +- public/ai-debate-case-generator/index.html | 16 +-- public/ai-debate-coach/index.html | 16 +-- public/ai-debate-practice/index.html | 16 +-- public/ai-rebuttal-generator/index.html | 16 +-- public/argument-flowchart/index.html | 16 +-- public/best-ai-debate-tools/index.html | 16 +-- .../british-parliamentary-debate/index.html | 16 +-- public/congress-debate/index.html | 16 +-- public/debate-clash-points/index.html | 16 +-- public/debate-evidence-finder/index.html | 16 +-- public/debate-fallacies/index.html | 16 +-- public/debate-judge-adaptation/index.html | 16 +-- public/debate-motion-analysis/index.html | 16 +-- public/debate-rebuttal-practice/index.html | 16 +-- public/debate-speech-structure/index.html | 16 +-- public/debate-topics-for-students/index.html | 16 +-- public/debatelab-pricing/index.html | 20 ++-- public/debatelab-vs-chatgpt/index.html | 16 +-- public/debatelab-vs-debateclub/index.html | 16 +-- public/debatelab-vs-windebate/index.html | 16 +-- .../how-to-cross-examine-in-debate/index.html | 16 +-- public/how-to-flow-in-debate/index.html | 16 +-- public/how-to-practice-rebuttals/index.html | 16 +-- .../index.html | 16 +-- public/how-to-weigh-in-debate/index.html | 16 +-- public/how-to-write-a-debate-case/index.html | 16 +-- public/humans.txt | 4 +- public/lincoln-douglas-debate/index.html | 16 +-- public/llms.txt | 110 +++++++++--------- public/online-debate-timer/index.html | 16 +-- public/policy-debate/index.html | 16 +-- public/public-forum-debate/index.html | 16 +-- public/robots.txt | 2 +- public/sw.js | 25 +++- public/world-schools-debate/index.html | 16 +-- scripts/check-site.mjs | 3 +- scripts/seo_hour_watch.py | 12 +- src/config/site.json | 4 +- src/locales/en.json | 2 +- src/locales/es.json | 2 +- src/locales/hu.json | 2 +- src/test/auth/auth-callback.test.ts | 8 +- src/test/checkout-security.test.ts | 4 +- src/test/seo/page-head.test.tsx | 6 +- src/test/service-worker-embed.test.ts | 51 ++++++-- src/test/supabase/local-preview-env.test.ts | 4 +- src/test/vercel-deployment-config.test.ts | 27 ++++- supabase/functions/_shared/cors.test.ts | 16 ++- supabase/functions/_shared/cors.ts | 5 +- .../functions/create-checkout/auth_test.ts | 4 +- .../create-checkout/checkout-security.ts | 1 + supabase/functions/create-portal/auth_test.ts | 2 +- .../functions/demo-code-login/index_test.ts | 2 +- supabase/functions/export-gdoc/auth_test.ts | 2 +- supabase/functions/share/auth_test.ts | 2 +- supabase/functions/workspace-invites/index.ts | 3 +- vercel.json | 6 + 68 files changed, 473 insertions(+), 380 deletions(-) diff --git a/.claude/skills/verify-debatelab/features/localization.md b/.claude/skills/verify-debatelab/features/localization.md index 2e7942b6b..00c72df2b 100644 --- a/.claude/skills/verify-debatelab/features/localization.md +++ b/.claude/skills/verify-debatelab/features/localization.md @@ -1,6 +1,6 @@ # Localization -The interface runs in English, Spanish and Hungarian. Every page names itself in the tab title in the interface language ("Generálás · DebateOwl" in the app, "Felhasználási feltételek | DebateOwl by Pi-Stack" on public pages), form validation and server refusals read in that language, the language switcher sits in every header, and `?lang=es|hu|en` links and the Hungarian and Spanish pages (`/hu`, `/es`, `/hu/tools/…`, `/es/tools/…`) open the app in that language. +The interface runs in English, Spanish and Hungarian. Every page names itself in the tab title in the interface language ("Generálás · DebateOwl" in the app, "Felhasználási feltételek | DebateOwl" on public pages), form validation and server refusals read in that language, the language switcher sits in every header, and `?lang=es|hu|en` links and the Hungarian and Spanish pages (`/hu`, `/es`, `/hu/tools/…`, `/es/tools/…`) open the app in that language. ## Sub-features diff --git a/AGENTS.md b/AGENTS.md index 1471baf2d..ae27cec78 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,7 +26,7 @@ The local Supabase stack still uses shared default ports and container names. In ## Deployment -The frontend is hosted on Vercel at `https://debate.pi-stack.org`. Merging to `main` starts a Vercel production deployment, so a merge ships the frontend. Supabase migrations and Edge Functions are not deployed to production by that merge; production deploys are separate authorized operations. Staging syncs itself from `main` within about 5 minutes through a VPS timer; [docs/staging.md](docs/staging.md) is the one place for staging access, seed data, and the sync. `npm run backend:status` (read-only) lists what the linked project is missing; run it before any backend deploy. +The frontend is hosted on Vercel at `https://debateowl.com`. Merging to `main` starts a Vercel production deployment, so a merge ships the frontend. Supabase migrations and Edge Functions are not deployed to production by that merge; production deploys are separate authorized operations. Staging syncs itself from `main` within about 5 minutes through a VPS timer; [docs/staging.md](docs/staging.md) is the one place for staging access, seed data, and the sync. `npm run backend:status` (read-only) lists what the linked project is missing; run it before any backend deploy. Vercel previews are opt-in. A push to `main` deploys both Vercel projects (production, and the staging project's site, which also tracks `main`). A push to any other branch does not create a deployment and does not count toward the daily cap. Request a hosted preview only when there is a real UI change to check. From the repo root, with the Vercel CLI logged in (`vercel login`, or `VERCEL_TOKEN` in the environment; never in the repo): diff --git a/README.md b/README.md index 22dc9b085..940c8985a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ DebateLab is an AI debate preparation and practice app for competitive debaters. Students keep one Current Debate for the motion they are preparing, build cases and research for both sides, and practise against the AI, with everything saved to that debate. -Live application: [debate.pi-stack.org](https://debate.pi-stack.org) +Live application: [debateowl.com](https://debateowl.com) (previously debate.pi-stack.org, which now redirects here) ## What it does diff --git a/docs/operations.md b/docs/operations.md index dbce274da..a8109bb30 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -36,7 +36,7 @@ If Actions jobs fail within 2 to 5 seconds with no runner and no logs, the accou ## Frontend hosting on Vercel -Vercel builds and serves the frontend from the Git repository. A push to `main` deploys both projects: `debate-navigator` to `https://debate.pi-stack.org`, and `debatelab-staging` to `https://debatelab-staging.vercel.app`. Any other branch waits for an explicit preview (see [Opt-in previews](#opt-in-previews)). For a staging-pinned preview on the tailnet, use `npm run dev:preview` (see [development.md](development.md#preview-on-the-tailnet)). The production canary runs after each successful Vercel `Production` deployment of `debate-navigator`. +Vercel builds and serves the frontend from the Git repository. A push to `main` deploys both projects: `debate-navigator` to `https://debateowl.com` (the previous domain, `https://debate.pi-stack.org`, 301s there with the path and query kept; see `vercel.json`), and `debatelab-staging` to `https://debatelab-staging.vercel.app`. Any other branch waits for an explicit preview (see [Opt-in previews](#opt-in-previews)). For a staging-pinned preview on the tailnet, use `npm run dev:preview` (see [development.md](development.md#preview-on-the-tailnet)). The production canary runs after each successful Vercel `Production` deployment of `debate-navigator`. [`vercel.json`](../vercel.json) owns: @@ -207,7 +207,7 @@ Local development origins must remain bounded to intended ports and hosts. ## Sign-in email and DNS -Production and staging Supabase Auth send sign-in codes from `DebateLab ` through Resend's SMTP relay (`smtp.resend.com`); the relay password lives only in each project's Auth settings. DNS for `pi-stack.org` is the Cloudflare zone. The sending records are: +Production and staging Supabase Auth send sign-in codes from `DebateOwl ` through Resend's SMTP relay (`smtp.resend.com`); the relay password lives only in each project's Auth settings. DNS for `pi-stack.org` is the Cloudflare zone. The records below are the ones set up for the previous sender, `auth@debate.pi-stack.org`; `debateowl.com` has the equivalent Resend records in its own Cloudflare zone. The previous sender's records are: - `send.debate.pi-stack.org`: Resend's SPF (`include:amazonses.com`) and bounce MX, so the bounce domain aligns with the From address. - `resend._domainkey.debate.pi-stack.org`: Resend's DKIM key; messages are signed with `d=debate.pi-stack.org`. @@ -238,7 +238,7 @@ Vercel build variables for Sentry source maps: `SENTRY_AUTH_TOKEN` (an organizat Choose rollback before changing production: -- Frontend: promote the previous known-good Vercel production deployment (about 10 seconds), or revert the commit on `main` and let Vercel redeploy (one to two minutes). The Vercel project is `debate-navigator`. `vercel inspect debate.pi-stack.org` shows the live deployment, `vercel ls debate-navigator --environment production --status READY` lists the earlier ones, and `vercel rollback --yes` switches back. On Adam's VPS, `~/ops/rollback/rollback vercel debate-navigator` does all three. After a rollback, Vercel stops putting new `main` deployments live until one is promoted with `vercel promote `, so promote the fixed deployment once it is ready. A frontend rollback does not touch Supabase: if the bad change came with a migration or function deploy, the old frontend must still work with the new backend. +- Frontend: promote the previous known-good Vercel production deployment (about 10 seconds), or revert the commit on `main` and let Vercel redeploy (one to two minutes). The Vercel project is `debate-navigator`. `vercel inspect debateowl.com` shows the live deployment, `vercel ls debate-navigator --environment production --status READY` lists the earlier ones, and `vercel rollback --yes` switches back. On Adam's VPS, `~/ops/rollback/rollback vercel debate-navigator` does all three. After a rollback, Vercel stops putting new `main` deployments live until one is promoted with `vercel promote `, so promote the fixed deployment once it is ready. A frontend rollback does not touch Supabase: if the bad change came with a migration or function deploy, the old frontend must still work with the new backend. - Edge Function: retain the deployed source or artifact baseline and its environment assumptions. - Migration: prefer forward corrective migrations. Do not assume an irreversible schema or data change can be rolled back. - Configuration: record the prior value without exposing secrets. diff --git a/docs/testing.md b/docs/testing.md index 463fe8e8b..16b7eaa0e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -288,7 +288,7 @@ PROD_SUPABASE_ANON_KEY=... PROD_CANARY_EMAIL=... PROD_CANARY_PASSWORD=... \ npx playwright test --config=playwright.production.config.ts ``` -`e2e/production/canary.spec.ts` checks `https://debate.pi-stack.org` directly: +`e2e/production/canary.spec.ts` checks `https://debateowl.com` directly: - the site loads and signed-out app routes redirect to Login; - every browser-facing Edge Function answers a preflight that allows the site origin (`workspace-invites` is excluded until production enables Workspaces); diff --git a/e2e/free-tools.spec.ts b/e2e/free-tools.spec.ts index c3b729577..c6baf0d87 100644 --- a/e2e/free-tools.spec.ts +++ b/e2e/free-tools.spec.ts @@ -1,6 +1,6 @@ import { test, expect, type Page } from '@playwright/test'; -const ORIGIN = 'https://debate.pi-stack.org'; +const ORIGIN = 'https://debateowl.com'; const TOOL_PAGES = [ { path: '/tools', h1: 'Free debate tools', type: 'CollectionPage' }, { path: '/tools/debate-timer', h1: 'Free debate timer for every format', type: 'WebApplication' }, diff --git a/e2e/loading-performance.spec.ts b/e2e/loading-performance.spec.ts index 1bb38a90b..101d46f38 100644 --- a/e2e/loading-performance.spec.ts +++ b/e2e/loading-performance.spec.ts @@ -19,7 +19,7 @@ test('a stalled Jam recorder cannot delay the real application', async ({ page, await page.evaluate(() => window.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }))); await jamRequest; await expect(page.getByRole('heading', { name: /: AI debate prep and practice$/ })).toBeVisible(); - await expect(page.getByText('DebateOwl by Pi-Stack is the official')).toHaveCount(0); + await expect(page.getByText('DebateOwl is the official')).toHaveCount(0); }); test('pagehide removes the Jam frame and a persisted pageshow does not re-add it (synthetic events, stubbed Jam)', async ({ page, browserName }) => { @@ -56,7 +56,7 @@ test('public routes keep the real UI after refresh', async ({ page }) => { await page.goto(path); await page.reload(); await expect(page.getByRole(path === '/' ? 'heading' : 'button', { name: label })).toBeVisible(); - await expect(page.getByText('DebateOwl by Pi-Stack is the official')).toHaveCount(0); + await expect(page.getByText('DebateOwl is the official')).toHaveCount(0); } }); @@ -72,7 +72,7 @@ test('authenticated routes keep the shell and current page after refresh', async await page.reload(); await expect(page.locator('header')).toBeVisible(); await expect(page.getByRole('heading', { name: heading, exact: true })).toBeVisible(); - await expect(page.getByText('DebateOwl by Pi-Stack is the official')).toHaveCount(0); + await expect(page.getByText('DebateOwl is the official')).toHaveCount(0); } }); diff --git a/e2e/localization.spec.ts b/e2e/localization.spec.ts index cd67e3da4..f4ce56ac0 100644 --- a/e2e/localization.spec.ts +++ b/e2e/localization.spec.ts @@ -68,7 +68,7 @@ test('every route has its own tab title in each language, and a switch retitles for (const language of ['en', 'es', 'hu'] as const) { for (const route of APP_ROUTES) expect(titles[language][route]).toMatch(/ · DebateOwl$/); - for (const route of PUBLIC_ROUTES) expect(titles[language][route]).toMatch(/ \| DebateOwl by Pi-Stack$/); + for (const route of PUBLIC_ROUTES) expect(titles[language][route]).toMatch(/ \| DebateOwl$/); } expect(titles.hu['/app/attack']).toBe(`${hu.nav.attack} · DebateOwl`); expect(titles.es['/no-such-page']).toBe(brand(es.pageHead.notFound.title)); diff --git a/embed/debate-timer/index.html b/embed/debate-timer/index.html index 644920858..de1cc7e65 100644 --- a/embed/debate-timer/index.html +++ b/embed/debate-timer/index.html @@ -8,7 +8,7 @@ out of search results in favour of the tool page. --> Debate timer | DebateOwl - + @@ -16,7 +16,7 @@
diff --git a/index.html b/index.html index 077aebae2..02b1df009 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ from it with their own title, description, canonical URL and JSON-LD. --> DebateOwl - + @@ -21,17 +21,17 @@ - - + + - + - + - +