<!-- source: openspec/changes/add-e2e-smoke-suite/tasks.md -->

<!-- source: openspec/changes/add-e2e-smoke-suite/tasks.md -->

# add-e2e-smoke-suite — tasks

## Phase 0 — operator gates + scaffolding (4 tasks)

- [ ] 0.1 Confirm `D-E2E-1..D-E2E-9` ratified by Pavel; confirm `Q-E2E-1` package-convention departure accepted.
- [ ] 0.2 **Operator:** create user `e2e@rapoport.studio` in Supabase Studio (project `nifagnmgwoqkplegsicy`). Confirm email via admin console. Set `app_metadata.platform_owner = true` via SQL per `design.md § D-E2E-8`.
- [ ] 0.3 **Operator:** seed one `specs` row owned by the e2e user. Since `specs.project_id` is `NOT NULL`, this requires either creating a parent `projects` row first or referencing an existing project. Capture the resulting `specs.id` UUID for `E2E_SEEDED_SPEC_ID`. Schema reference: `openspec/current/db/entities.md § Project → spec → idea hierarchy` (applied 2026-05-22 from change `rearchitect-spec-document-model`, RAP-1170). The legacy `canvas_sessions` table referenced in earlier drafts of this spec no longer exists.
- [ ] 0.4 **Operator:** populate GitHub Actions environment `production-e2e` with the seven secrets/vars from `design.md § D-E2E-3` table. Confirm `TELEGRAM_BOT_TOKEN` + `TELEGRAM_OPERATOR_CHAT_ID` already present at repo level (precedent: marketing-funnel-instrumentation Phase 5).

## Phase 1 — package skeleton (5 tasks)

- [ ] 1.1 Create `packages/e2e/package.json` with `name: "@rapoport-studio/e2e"`, `private: true`, `version: "0.0.0"`, `type: "module"`, scripts `test` / `test:headed` / `test:debug` / `typecheck`. Dependencies: `@playwright/test ^1.50`, `@supabase/supabase-js ^2`. Dev: `typescript`, `@types/node`.
- [ ] 1.2 Create `packages/e2e/tsconfig.json` extending the repo root tsconfig; `include: ["src/**/*", "tests/**/*", "global-setup.ts", "playwright.config.ts"]`.
- [ ] 1.3 Create `packages/e2e/.gitignore` covering `playwright-report/`, `playwright/.auth/`, `test-results/`, `node_modules/`.
- [ ] 1.4 Create `packages/e2e/playwright.config.ts` per `design.md § playwright.config.ts shape`. Single Chromium project, `globalSetup` ref, `fullyParallel: false`, `workers: 1`, `retries: 1`.
- [ ] 1.5 Create `packages/e2e/README.md` covering: what the harness is, the operator runbook (links back to `design.md § D-E2E-8`), how to run locally, the weekly cleanup SQL, and a "this is not a library" disclaimer for the package-convention departure.

## Phase 2 — auth fixture + global setup (3 tasks)

- [ ] 2.1 Create `packages/e2e/src/fixtures/supabase.ts` exporting `createE2EServiceClient(): SupabaseClient` reading `SUPABASE_URL` + `SUPABASE_SERVICE_ROLE_KEY` from `process.env`. Throws if either is missing.
- [ ] 2.2 Create `packages/e2e/src/fixtures/auth.ts` exporting `mintMagicLink(email): Promise<string>` per `design.md § Auth fixture detail`. Resolves to the full `${E2E_STUDIO_URL}/auth/confirm?...` URL.
- [ ] 2.3 Create `packages/e2e/global-setup.ts` per `design.md § Auth fixture detail`. Mints link, drives Chromium through `/auth/confirm`, saves `playwright/.auth/storage.json`. Throws on redirect timeout.

## Phase 3 — smoke tests (6 tasks)

- [ ] 3.1 `packages/e2e/tests/web/apex.spec.ts` — assert `${E2E_WEB_URL}/` returns 200; `<h1>` matches expected hero copy (read from `apps/web/messages/en/common.json § hero.headline` — store the expected string inline with a comment pointing to the source key).
- [ ] 3.2 `packages/e2e/tests/web/services.spec.ts` — `${E2E_WEB_URL}/services` 200; at least one `a[href^="/services/"]` link rendered.
- [ ] 3.3 `packages/e2e/tests/web/intake.spec.ts` — navigate to `${E2E_WEB_URL}/contact`; fill `name`, `email: 'e2e+contact@rapoport.studio'`, `message: 'e2e smoke'`; submit; assert success state. The submission MUST include `metadata: { e2e: true }` (per `design.md § Test data shape`); add a regression-style comment in the test pointing to that section.
- [ ] 3.4 `packages/e2e/tests/studio/login.spec.ts` — uses `storageState: { cookies: [], origins: [] }` (anonymous). Asserts `${E2E_STUDIO_URL}/login` 200; email input + submit button render.
- [ ] 3.5 `packages/e2e/tests/studio/workspace.spec.ts` — uses default storageState (authenticated). Asserts `${E2E_STUDIO_URL}/` 200; workspace home shell renders; no error banner.
- [ ] 3.6 `packages/e2e/tests/studio/spec-smoke.spec.ts` — uses default storageState. Asserts `${E2E_STUDIO_URL}/spec/${E2E_SEEDED_SPEC_ID}` 200; Architect chat surface renders (textarea selector). The seeded row is empty in v1, so no historical-message assertion.

## Phase 4 — GitHub Actions workflow (3 tasks)

- [ ] 4.1 Author `.github/workflows/e2e-prod.yml` per `design.md § GitHub Actions workflow shape`. `schedule: '0 6,18 * * *'` + `workflow_dispatch`. References `environment: production-e2e`.
- [ ] 4.2 Wire `playwright install chromium --with-deps` as a workflow step. Verify with `actionlint` locally (no errors).
- [ ] 4.3 Wire trace-artefact upload (`actions/upload-artifact@v4`) with 90-day retention, gated on `if: failure()`.

## Phase 5 — Telegram alert wiring (2 tasks)

- [ ] 5.1 Add the `if: failure()` Telegram POST step per `design.md § D-E2E-7`. Markdown-formatted, single message per run (not per test). Includes workflow run URL.
- [ ] 5.2 Manual smoke: trigger `workflow_dispatch` with a temporarily broken assertion in `apex.spec.ts` (e.g. wrong H1); confirm Telegram message arrives in operator chat; revert the broken assertion.

## Phase 6 — archive amendments (2 tasks)

> Per `AGENTS.md § What gets amended where, and when` — these only land at archive time, **not** during implementation.

- [ ] 6.1 Amend `openspec/current/platform.md` — append section `## E2E smoke suite (applied YYYY-MM-DD from change add-e2e-smoke-suite)` noting the harness, schedule, and target. One paragraph.
- [ ] 6.2 Amend `openspec/current/auth.md` — append section `## E2E test auth path (applied YYYY-MM-DD from change add-e2e-smoke-suite)` documenting the `auth.admin.generateLink` + `/auth/confirm` flow as a supported test path. One paragraph.

## Phase 7 — verification (1 task)

- [ ] 7.1 All `verification.md § Acceptance` deterministic assertions pass. `pnpm --filter @rapoport-studio/e2e typecheck` returns 0. First scheduled workflow run completes green (or the manual `workflow_dispatch` does).

**Total: 26 tasks across 8 phases.**
