Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/verify-debatelab/features/localization.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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):

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 3 additions & 3 deletions docs/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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 <auth@debate.pi-stack.org>` 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 <auth@debateowl.com>` 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`.
Expand Down Expand Up @@ -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 <previous-deployment-url> --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 <deployment-url>`, 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 <previous-deployment-url> --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 <deployment-url>`, 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.
Expand Down
2 changes: 1 addition & 1 deletion docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion e2e/free-tools.spec.ts
Original file line number Diff line number Diff line change
@@ -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' },
Expand Down
6 changes: 3 additions & 3 deletions e2e/loading-performance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand Down Expand Up @@ -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);
}
});

Expand All @@ -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);
}
});

Expand Down
2 changes: 1 addition & 1 deletion e2e/localization.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
4 changes: 2 additions & 2 deletions embed/debate-timer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
out of search results in favour of the tool page. -->
<title>Debate timer | DebateOwl</title>
<meta name="robots" content="noindex" />
<link rel="canonical" href="https://debate.pi-stack.org/tools/debate-timer" />
<link rel="canonical" href="https://debateowl.com/tools/debate-timer" />
<link rel="icon" href="/favicon.ico" sizes="48x48" />
<link rel="icon" type="image/png" href="/favicon.png" sizes="48x48" />
<script src="/src/embed/debate-timer.tsx" type="module"></script>
</head>
<body>
<div id="root"></div>
<noscript>
<p style="font-family: system-ui, sans-serif; padding: 16px;">This timer needs JavaScript. <a href="https://debate.pi-stack.org/tools/debate-timer" target="_blank" rel="noopener">Open the debate timer by DebateOwl</a>.</p>
<p style="font-family: system-ui, sans-serif; padding: 16px;">This timer needs JavaScript. <a href="https://debateowl.com/tools/debate-timer" target="_blank" rel="noopener">Open the debate timer by DebateOwl</a>.</p>
</noscript>
</body>
</html>
14 changes: 7 additions & 7 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from it with their own title, description, canonical URL and JSON-LD. -->
<title>DebateOwl</title>
<meta name="description" content="DebateOwl is an AI debate prep and practice app for students and debaters: cases, rebuttals, evidence, coaching and timed rounds against an AI opponent." />
<meta name="author" content="DebateOwl by Pi-Stack" />
<meta name="author" content="Pi-Stack" />
<!-- The shell for /app, /login and /share. Prerender replaces this with the
public index directive on pages that have a canonical URL. -->
<meta name="robots" content="noindex, nofollow" />
Expand All @@ -21,17 +21,17 @@
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
<link rel="manifest" href="/manifest.webmanifest" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="DebateOwl by Pi-Stack" />
<meta property="og:title" content="DebateOwl by Pi-Stack | AI Debate Prep, Cases & Rebuttals" />
<meta property="og:site_name" content="DebateOwl" />
<meta property="og:title" content="DebateOwl | AI Debate Prep, Cases & Rebuttals" />
<meta property="og:description" content="DebateOwl is an AI debate prep and practice app for students and debaters: cases, rebuttals, evidence, coaching and timed rounds against an AI opponent." />
<meta property="og:image" content="https://debate.pi-stack.org/hero-visual.jpg?v=2" />
<meta property="og:image" content="https://debateowl.com/hero-visual.jpg?v=2" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="DebateOwl wordmark with the owl, for AI debate prep and practice" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="DebateOwl by Pi-Stack | AI Debate Prep" />
<meta name="twitter:title" content="DebateOwl | AI Debate Prep" />
<meta name="twitter:description" content="DebateOwl is an AI debate prep and practice app for students and debaters: cases, rebuttals, evidence, coaching and timed rounds against an AI opponent." />
<meta name="twitter:image" content="https://debate.pi-stack.org/hero-visual.jpg?v=2" />
<meta name="twitter:image" content="https://debateowl.com/hero-visual.jpg?v=2" />
<meta name="twitter:image:alt" content="DebateOwl wordmark with the owl, for AI debate prep and practice" />
<script src="/theme-init.js"></script>
<style>
Expand Down Expand Up @@ -160,7 +160,7 @@
</div>
<noscript>
<main style="max-width: 40rem; margin: 0 auto; padding: 48px 20px; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; line-height: 1.6;">
<h1>DebateOwl by Pi-Stack</h1>
<h1>DebateOwl</h1>
<p>DebateOwl needs JavaScript to run. Read about it on the <a href="/">home page</a> or in the <a href="/ai-debate-practice">AI debate practice guide</a>.</p>
</main>
</noscript>
Expand Down
2 changes: 1 addition & 1 deletion playwright.production.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default defineConfig({
reporter: process.env.CI ? [["github"], ["list"]] : "list",
expect: { timeout: 20_000 },
use: {
baseURL: process.env.PROD_URL ?? "https://debate.pi-stack.org",
baseURL: process.env.PROD_URL ?? "https://debateowl.com",
locale: "en-US",
trace: "off",
screenshot: "off",
Expand Down
Loading
Loading