Skip to content
Draft
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
4 changes: 4 additions & 0 deletions .cursor/skills/verify-samehere/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.run/
helpers/node_modules/
artifacts/**
!artifacts/README.md
151 changes: 151 additions & 0 deletions .cursor/skills/verify-samehere/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
name: verify-samehere
description: Drive the samehere Next.js web app (landing, signup, login, pricing, public profiles) in a real Chrome session the way a user does. Use when proving UI behavior, checking a local instance, or capturing verification evidence.
---

# Verify samehere

samehere is a Next.js 16 App Router web app (`npm run dev`, default product port 3000). There is no Playwright/Cypress suite and no CLI surface. Verification launches an isolated `next dev` on **127.0.0.1:4173**, then drives Chrome through `control-samehere browser` (Playwright-core over CDP against system `google-chrome`).

Read [features/README.md](features/README.md) before driving. The map is the source of truth; proving one convenient entry point is incomplete when a feature file lists others.

Signed-in product surfaces (`/feed`, `/search`, `/messages`, `/settings`, `/jobs`, `/community`, `/dashboard`) require a real Supabase session. This skill does not mint accounts. If `doctor` reports `env_mode=scaffolded`, treat those routes as unreachable (they 307 to `/signup`).

## Launch

One verification instance per checkout. `next dev` writes `.next/` in the repo; a second Next process on the same worktree will corrupt the session. `launch` refuses if port 4173 is taken or if another `next` is already running from this repo.

```bash
# From the repo root. Install helper deps once per machine.
npm install --prefix .cursor/skills/verify-samehere/helpers --omit=dev --no-fund --no-audit

.cursor/skills/verify-samehere/helpers/control-samehere launch
# optional: --port 4173 --host 127.0.0.1
```

Ready when `launch` prints `ok url=http://127.0.0.1:4173` and `GET /` returns HTML containing `samehere`. The helper polls for up to 90s (first compile downloads `next/font` Google faces).

What launch does:

- Starts `npm run dev -- --hostname 127.0.0.1 --port 4173` in its own process group.
- Sets `SAMEHERE_VERIFY=1`, `SAMEHERE_VERIFY_RUN_ID`, `PORT`, `HOSTNAME`.
- If `.env.local` exists, Next loads it (`env_mode=repo`). Do not overwrite it.
- If `.env.local` is missing, launch exports a **verification-scaffolding** Supabase URL/anon JWT and `NEXT_PUBLIC_SITE_URL=http://127.0.0.1:4173` (`env_mode=scaffolded`). Those values live only in the process environment and `.run/`; they are not written into the repo. Landing, login/signup forms, pricing, and legal pages still render. Auth mutations and live profile RPCs do not.
- Unsets `INVITE_ONLY` in the scaffolded case so OAuth buttons stay visible. A repo `.env.local` with `INVITE_ONLY=1` hides them (`invite_only=yes`).

State: `.cursor/skills/verify-samehere/.run/` (pid, port, run id, next.log, chrome profile). Gitignored.

Teardown is `control-samehere cleanup` (see Cleanup). Never `pkill -f next`.

## Doctor

Read-only. Run before the first drive, after any failed drive, and whenever the instance looks off.

```bash
.cursor/skills/verify-samehere/helpers/control-samehere doctor
```

Pass means all of:

- `.run/pid` is alive.
- Port `4173` (or the launched port) is owned by that process group.
- `GET /` is `200` and the body contains `samehere`.
- Printed `url`, `run_id`, `env_mode`, `invite_only`, `landing=yes|no`, and `<title>`.

Fail → fix or `cleanup` + `launch`. Do not drive an instance this run did not start.

`env_mode=scaffolded` prints a note: skip live signup/login success and published-profile proofs.

## Drive

Harness is `control-samehere`. Browser actions use Playwright `getByRole` against a **1280×800** desktop viewport (landing `Log in` / `Join free` are `hidden md:inline-flex`; a mobile width hides them). Each `browser` command connects over CDP, prints `ok …`, and exits so the WebSocket does not hold the shell; Chrome stays up until `cleanup`.

```bash
BIN=.cursor/skills/verify-samehere/helpers/control-samehere

$BIN browser goto --path /
$BIN browser click --role link --name "Join free" --nth 0
$BIN browser fill --role textbox --name "Email" --value "you@school.edu"
$BIN browser press --key Enter --role textbox --name "Email"
$BIN browser wait --text "Create your account"
$BIN browser snapshot --aria --path artifacts/landing/signup.aria.txt
$BIN browser screenshot --path artifacts/landing/signup.png
$BIN browser url
$BIN http get --path /feed --expect-status 307
```

Stable handles from this repo (prefer these over CSS or coordinates):

| Surface | Handle |
|---|---|
| Brand | `link` name `samehere home` |
| Landing desktop nav | `link` `Log in`, `link` `Join free` (nth 0 is the header). Section links `Product`, `Community`, `Pricing` inside `navigation` `Page sections`. |
| Landing hero | heading text includes `Find your people` / `Show what you’re building.`; primary CTA `Join free`; secondary `Explore the community` (`#community`). |
| Community demo | `tablist` `Product areas` with tabs `Feed`, `Messages`, `Portfolio`. `#community` is this block, not the later invite band. |
| Pricing block | `#pricing`, heading `Share your work. Make your portfolio your own.`, articles `Share work and find peers` / `More room to present your work`, `Join free`, `View Pro`. |
| Footer | `navigation` `Footer`: `Pricing`, `Terms`, `Privacy`, `Sign up`. |
| Signup | heading `Create your account`; textboxes `Email`, `Username`, `Password`, `Referral code` (or `Invite code` when `invite_only=yes`); buttons `Create account`, `Continue with Google`, `Continue with GitHub`; link `Log in`. |
| Login | heading `Log in`; textboxes `Email`, `Password`; button `Log in`; links `Forgot password?`, `Create an account`. |
| Login errors | `alert` `Enter your email and password.` (empty submit if the browser allows it) or `Invalid email or password.` |
| Signup errors | `alert` with `Username must be 3-20 characters…`, `That username is reserved.`, `Password must be at least 8 characters.` |
| Pricing page | `/pricing`, heading same as the landing block, header `Join free`. |
| Missing profile | `/profile/<unknown>` → `Profile not found`. |

`--nth` is 0-based among matches. Duplicate names (`Join free`, `Log in`) are everywhere; the feature file says which nth.

Do not click `Continue with Google` / `Continue with GitHub` — those hit real IdPs. Do not submit a successful signup against a live `.env.local`.

Anon `/feed` (and any other gated path) is `307` to `/signup`. Confirm with `http get`, not by treating the signup HTML as the feed.

## Evidence

Write under `.cursor/skills/verify-samehere/artifacts/<feature-id>/`. Relative `artifacts/...` paths given to `browser snapshot` / `screenshot` resolve there. Cleanup must not touch this tree.

Proof standards:

- Drive the real user path (click the same links a person uses). Do not call server actions, RPCs, or test-only URLs to fake a state.
- Capture the **action** and the **resulting state** (ARIA snapshot + screenshot). A final screen alone is not enough.
- UI proof must show samehere identity: the `samehere home` brand and the page heading.
- HTTP side effects: record status + `Location` for redirects (`http get`).
- Auth: HTML5 `required` may block an empty submit; that is a real user-visible outcome — snapshot the still-on-page form, do not invent an `alert`.
- Mocks: the scaffolded Supabase URL is a launch fallback so middleware can construct a client. It is not a stand-in for a successful login, signup, or published profile. Observe what it actually skips (`env_mode=scaffolded`, failed RPCs → `Profile not found`, login `alert` `Invalid email or password.` or a generic create-account failure).
- Record feature ID, entry point, URL, and `run_id` in `artifacts/<feature-id>/run.json`.

## Cleanup

```bash
.cursor/skills/verify-samehere/helpers/control-samehere cleanup
```

Kills the exact Next.js process group recorded at launch and the Chrome PID in `.run/chrome_pid`. Deletes `.run/` (logs, chrome profile, pid files). Leaves `artifacts/` in place.

Run cleanup after every failed iteration too, then launch again. If launch itself fails mid-start, it already calls cleanup.

Never `pkill -f next`, `pkill -f chrome`, or kill by window title.

## Helpers

All invocations assume the repo root. `control-samehere` is executable.

```bash
chmod +x .cursor/skills/verify-samehere/helpers/control-samehere # once, if git dropped +x

.cursor/skills/verify-samehere/helpers/control-samehere launch
.cursor/skills/verify-samehere/helpers/control-samehere doctor
.cursor/skills/verify-samehere/helpers/control-samehere browser goto --path /
.cursor/skills/verify-samehere/helpers/control-samehere cleanup
```

`helpers/lib/browser.mjs` is the CDP driver. `helpers/package.json` pins `playwright-core` only (system Chrome, no browser download). The first `browser` command runs `npm install` in `helpers/` if `node_modules` is missing.

Optional env:

- `SAMEHERE_VERIFY_PORT` / `--port` — default `4173`
- `SAMEHERE_VERIFY_HOST` / `--host` — default `127.0.0.1`
- `SAMEHERE_VERIFY_STATE_DIR` — default `<skill>/.run`
- `SAMEHERE_VERIFY_ARTIFACTS_DIR` — default `<skill>/artifacts`
- `SAMEHERE_VERIFY_CHROME` — Chrome binary (use the real binary, not a wrapper that shares the desktop profile)
- `SAMEHERE_VERIFY_CDP_PORT` — Chrome DevTools port, default `14173`
- `SAMEHERE_VERIFY_PROFILE_USERNAME` — live username for the published-profile path

Keep the map honest with `/maintain-verification-skill` as the app changes.
13 changes: 13 additions & 0 deletions .cursor/skills/verify-samehere/artifacts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Verification evidence

Proof artifacts for a verify-samehere run live here, one subdirectory per feature ID (`landing/`, `signup/`, `login/`, `pricing/`, `public-profile/`).

Cleanup tears down the Next.js process, the Chrome session, and `/tmp` scratch state. It never deletes this directory.

Typical files for a UI proof:

- `01-home.png` / `01-home.aria.txt` — starting surface
- `02-<action>.png` / `02-<action>.aria.txt` — the user action's resulting state
- `run.json` — feature ID, entry point, URL, run ID, doctor excerpt

Name files so the action and the result stay paired. Do not overwrite another run's files; use a fresh subdirectory or a timestamped prefix if you need to keep both.
50 changes: 50 additions & 0 deletions .cursor/skills/verify-samehere/features/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# samehere verification map

This directory is the maintained source for verifying the user-facing behavior of samehere. Read the index before driving the app, then use the matching feature file as the recipe.

## Baseline preconditions

- Launch samehere at `http://127.0.0.1:4173` with `control-samehere launch`.
- Run `control-samehere doctor` and require `url=http://127.0.0.1:4173`, a live pid that owns that port, and `landing=yes`.
- Drive at a 1280×800 desktop viewport (the helper sets this). Mobile widths hide `Log in` / `Join free`.
- Never drive an instance that was not started by this verification run.
- If `env_mode=scaffolded`, do not report live signup, live login, or a published public profile as verified. Form chrome, validation alerts, marketing pages, and `Profile not found` remain in scope.
- If `invite_only=yes`, signup requires `Invite code` and OAuth buttons are hidden on login and signup.
- Do not click `Continue with Google` or `Continue with GitHub`.

## Driving conventions

- Start every recipe from the baseline state unless its preconditions say otherwise.
- Prefer ARIA roles and accessible names over CSS selectors or DOM position.
- Treat every command as literal. Keep quoted names and flags unchanged.
- Run browser actions through `control-samehere browser`.
- Run redirect checks through `control-samehere http get`.
- Restore the browser to `/` after a mutation-like navigation if the next recipe needs the landing. Do not remove proof artifacts during cleanup.

## Proof and skip reporting

- Capture the user action and the resulting state, not only the final screen.
- UI proof includes an ARIA snapshot and a screenshot with the samehere brand visible.
- Redirect proof includes status and `Location`.
- Record the feature ID and entry point used with every artifact (`artifacts/<id>/run.json`).
- Report an unreachable path with the attempted command and the unmet precondition (`env_mode=scaffolded`, missing `SAMEHERE_VERIFY_PROFILE_USERNAME`, no session).
- Do not report a skipped entry point as verified through a different path.

## Feature entry contract

Each feature file starts with an H1 title and one paragraph describing the user-visible behavior. It then uses exactly four H2 sections in this order.

1. `Sub-features` lists short IDs with one line for each behavior.
2. `How to get to it (user POV)` lists every user entry point.
3. `Driving it with control-samehere` starts with `Preconditions:` and uses labeled bullets that pair each user action with an exact command and observable result.
4. `Gotchas` lists traps that can waste or invalidate a verification run.

Keep implementation details out of the map. Name only user paths, stable handles, required state, commands, and observable proof.

## Features

- [Landing](./landing.md) covers the logged-out home page: hero, section nav, community tabs, pricing band, and CTAs into signup/login.
- [Sign up](./signup.md) covers the create-account form, validation, footer cross-link, and the invite-only variant.
- [Log in](./login.md) covers the login form, forgot-password, and the anonymous redirect into auth.
- [Pricing](./pricing.md) covers `/pricing` and the landing `#pricing` band, including the Pro link.
- [Public profile](./public-profile.md) covers a missing username and, when a live project is configured, a published `/profile/<username>` page.
44 changes: 44 additions & 0 deletions .cursor/skills/verify-samehere/features/landing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Landing

The logged-out home page at `/` is the marketing surface: a hero, in-page Product / Community / Pricing sections, a community demo, a pricing band, and CTAs that take a visitor to signup or login.

## Sub-features

- `landing-open` renders the hero with samehere identity and the primary Join CTA.
- `landing-nav-login` opens `/login` from the desktop header.
- `landing-nav-join` opens `/signup` from the desktop header.
- `landing-nav-sections` jumps to `#product`, `#community`, and `#pricing` from `Page sections`.
- `landing-community-tabs` switches the Product areas tabs without leaving `/`.
- `landing-footer` reaches Pricing, Terms, Privacy, and Sign up from the footer.

## How to get to it (user POV)

- Open `http://127.0.0.1:4173/` in a logged-out browser.
- Choose the `samehere home` brand from login, signup, pricing, terms, or privacy.
- Follow a marketing link that points at `/` (no `?code=` query — that is forwarded to `/auth/callback`).

## Driving it with control-samehere

Preconditions:

- samehere is healthy at `http://127.0.0.1:4173`.
- `control-samehere doctor` reports `landing=yes` and this run's URL.
- The browser has no `sb-*-auth-token` cookie (a signed-in visitor is redirected to `/feed`).

- **Open landing.** Load `/`. Run `control-samehere browser goto --path /`. The document title contains `samehere`, a `link` named `samehere home` is visible, and the hero heading includes `people` and `Show what you’re building.`
- **Header login.** Choose `Log in`. Run `control-samehere browser click --role link --name "Log in" --nth 0`. The URL is `http://127.0.0.1:4173/login` and the heading reads `Log in`.
- **Return home.** Choose the brand. Run `control-samehere browser click --role link --name "samehere home" --nth 0`. The URL is `http://127.0.0.1:4173/` and the hero is visible again.
- **Header join.** Choose `Join free` in the header. Run `control-samehere browser click --role link --name "Join free" --nth 0`. The URL is `http://127.0.0.1:4173/signup` and the heading reads `Create your account`.
- **Hero join (second entry).** Return home, then choose the hero `Join free`. Run `control-samehere browser goto --path /` and `control-samehere browser click --role link --name "Join free" --nth 1`. The URL is `/signup` again.
- **Section nav.** Return home. Run `control-samehere browser goto --path /`, then `control-samehere browser click --role link --name "Product"`, `Community`, and `Pricing` in turn. After `Product` a heading `Give your project a story.` is in view. After `Community` a heading `Talk it through.` is in view. After `Pricing` a heading `Share your work. Make your portfolio your own.` is in view. The URL hash is `#product`, `#community`, and `#pricing` respectively.
- **Community tabs.** On `/` (or `#community`) choose `Messages`. Run `control-samehere browser click --role tab --name "Messages"`. The selected tab is `Messages` and the panel text includes `Talk with people on a similar path.` Choose `Portfolio`, then `Feed`, and confirm each selected tab's description: `Keep a shareable project page at your username.` / `Share what you are building, learning, or stuck on.`
- **Footer legal.** From `/` choose `Terms` in the footer. Run `control-samehere browser click --role link --name "Terms"`. The heading reads `Terms of Service`. Choose `samehere home`, then footer `Privacy`. The heading reads `Privacy Policy`.
- **Proof.** Recapture the populated landing. Run `control-samehere browser goto --path /`, `control-samehere browser snapshot --aria --path artifacts/landing/home.aria.txt`, and `control-samehere browser screenshot --path artifacts/landing/home.png`. Both artifacts show the samehere brand and the hero heading. After the join click, also keep `artifacts/landing/signup.png` and `artifacts/landing/signup.aria.txt` so the CTA result is paired with the start state. Write `artifacts/landing/run.json` with feature ID `landing`, the entry point used, the URL, and `run_id`.

## Gotchas

- At viewports below `md`, header `Log in` / `Join free` are not rendered. The helper viewport is 1280×800; do not shrink it and then report those links missing.
- Several `Join free` links exist (header, hero, community invite, pricing, finale). `--nth 0` is the header; `--nth 1` is the hero. Snapshot the URL after the click instead of guessing by visual position.
- `#community` is the "Talk it through." demo (`SocialPreview`), not the later "Bring your classmates…" invite band.
- A signed-in session on `/` 307s to `/feed`. If doctor still says `landing=yes` over HTTP but the browser shows the feed, the Chrome profile kept auth cookies — `cleanup` and relaunch.
- `/?code=...` is not the landing; middleware forwards it to `/auth/callback`.
Loading
Loading