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
102 changes: 79 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,28 @@ on:
pull_request:
branches: [main]

env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/together
ROOM_TOKEN_SECRET: test-secret
NEXT_PUBLIC_APP_URL: http://localhost:3000
NEXT_PUBLIC_REALTIME_URL: ws://localhost:8787

jobs:
lint-and-typecheck:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm ci:quality

build:
runs-on: ubuntu-latest
needs: quality
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
Expand All @@ -20,11 +39,37 @@ jobs:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- run: pnpm lint
- run: pnpm ci:build

unit:
runs-on: ubuntu-latest
needs: quality
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm ci:unit

db:
runs-on: ubuntu-latest
needs: quality
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm ci:db

test:
runs-on: ubuntu-latest
needs: [build, unit, db]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
Expand All @@ -33,16 +78,25 @@ jobs:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @together/web test:install
- run: pnpm --filter @together/web test
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/together
ROOM_TOKEN_SECRET: test-secret
NEXT_PUBLIC_APP_URL: http://localhost:3000
NEXT_PUBLIC_REALTIME_URL: ws://localhost:8787
- run: pnpm ci:e2e
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ github.job }}-${{ github.run_id }}
path: apps/web/playwright-report/
retention-days: 14
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ github.job }}-${{ github.run_id }}
path: apps/web/test-results/
retention-days: 14

visual:
runs-on: ubuntu-latest
needs: [build, unit, db]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
Expand All @@ -51,16 +105,18 @@ jobs:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @together/web test:install
- run: pnpm --filter @together/web test:mobile
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/together
ROOM_TOKEN_SECRET: test-secret
NEXT_PUBLIC_APP_URL: http://localhost:3000
NEXT_PUBLIC_REALTIME_URL: ws://localhost:8787
- run: pnpm --filter @together/web test:visual
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/together
ROOM_TOKEN_SECRET: test-secret
NEXT_PUBLIC_APP_URL: http://localhost:3000
NEXT_PUBLIC_REALTIME_URL: ws://localhost:8787
- run: pnpm ci:visual
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ github.job }}-${{ github.run_id }}
path: apps/web/playwright-report/
retention-days: 14
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ github.job }}-${{ github.run_id }}
path: apps/web/test-results/
retention-days: 14
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ playwright-report
test-results
coverage
.DS_Store
.husky/pre-commit.local
.husky/pre-push.local
# Husky generates .husky/_/ on install (see .husky/_/.gitignore); do not commit that folder.
# Local know-code state (per developer — not committed)
.know-code/
7 changes: 7 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env sh
[ "$SKIP_HOOKS" = "1" ] && exit 0
pnpm ci:pre-commit
# Optional machine-local extensions (gitignored) - e.g. know-code quiz gate
if [ -f "$(dirname -- "$0")/pre-commit.local" ]; then
. "$(dirname -- "$0")/pre-commit.local"
fi
7 changes: 7 additions & 0 deletions .husky/pre-commit.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Optional know-code overlay for pre-commit — intentionally empty in range mode.
#
# know-code gates push (pre-push.local), not each commit. While a range is open,
# land all commits first, then teach → quiz → pass → range seal → push.
#
# If you use index mode (quiz per commit) instead of range mode, copy the check
# from pre-push.local.example here — see CONTRIBUTING.md.
7 changes: 7 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env sh
[ "$SKIP_HOOKS" = "1" ] && exit 0
pnpm ci:pre-push
# Optional machine-local extensions (gitignored) - e.g. know-code quiz gate
if [ -f "$(dirname -- "$0")/pre-push.local" ]; then
. "$(dirname -- "$0")/pre-push.local"
fi
20 changes: 20 additions & 0 deletions .husky/pre-push.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copy to .husky/pre-push.local to enable (file is gitignored).
#
# [know-code](https://kc.chtnnhfoundation.org) blocks push until the range is sealed
# and comprehension checks pass. Runs after shared ci:pre-push checks.
#
# cp .husky/pre-push.local.example .husky/pre-push.local

run_know_code_check() {
ROOT="$(git rev-parse --show-toplevel)"
if [ -x "$ROOT/node_modules/.bin/know-code" ]; then
"$ROOT/node_modules/.bin/know-code" check
elif command -v know-code >/dev/null 2>&1; then
know-code check
else
echo "know-code: CLI not found. Install: npm i -g @chtnnh/know-code" >&2
exit 1
fi
}

run_know_code_check
9 changes: 8 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,21 @@ Monorepo for **Together** (synced YouTube watch/listen rooms). Default branch: *

```bash
pnpm install --frozen-lockfile
pnpm lint # Biome check
pnpm format # Biome write
pnpm typecheck
pnpm lint
pnpm test:unit # Vitest (all packages)
pnpm ci:local # Full merge gate (same as CI)
pnpm ci:pre-commit # Hook: incremental checks
pnpm ci:pre-push # Hook: quality + affected unit/build (no E2E/visual)
pnpm --filter @together/web test:install # first time / CI
pnpm --filter @together/web test
pnpm --filter @together/realtime dev # requires Node 22+
pnpm --filter @together/web dev
```

See **`CONTRIBUTING.md`** for merge gate contract, hook tiers, and viewing CI Playwright artifacts.

Env is loaded from repo root `.env` (see `.env.example`). Do not commit secrets.

## Conventions
Expand Down
126 changes: 126 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Contributing to Together

## Merge gate contract

**Green CI = safe to merge** (after you review intent). GitHub Actions runs the full suite via `pnpm ci:local` scripts:

| Job | Script | What it checks |
|-----|--------|----------------|
| `quality` | `pnpm ci:quality` | Biome lint/format + TypeScript |
| `build` | `pnpm ci:build` | Next.js + realtime worker build |
| `unit` | `pnpm ci:unit` | Vitest across all packages |
| `db` | `pnpm ci:db` | Drizzle journal / migration integrity |
| `test` | `pnpm ci:e2e` | Playwright E2E (desktop + mobile) |
| `visual` | `pnpm ci:visual` | Visual regression (Linux Docker baselines) |

Run the same locally before opening a PR:

```bash
pnpm install --frozen-lockfile
pnpm ci:local
```

## Git hooks (incremental)

Hooks catch most issues early without running the full ~15-minute suite on every commit.

**Shared hooks are committed** in `.husky/pre-commit` and `.husky/pre-push` — every contributor gets them after `pnpm install` (the `prepare` script runs Husky and wires Git’s `core.hooksPath`). Only **optional** know-code overlays (`.husky/*.local`) are gitignored.

| Hook | Command | Typical duration |
|------|---------|------------------|
| **pre-commit** | `pnpm ci:pre-commit` | ~30–90s |
| **pre-push** | `pnpm ci:pre-push` | ~1-5 min |

**pre-commit:** `lint-staged` (Biome auto-fix), Biome on changed files, affected typecheck, Vitest `--changed`, DB guard if `schema.ts` changed.

**pre-push:** full Biome, affected typecheck/unit, conditional build, DB guard if schema changed. Large diffs (>30 files) or CI infra changes run full quality + build + unit + db (no E2E/visual; CI covers those).

Skip hooks when necessary (you are responsible for CI):

```bash
SKIP_HOOKS=1 git commit
SKIP_HOOKS=1 git push
# or
git push --no-verify
```

## Optional: know-code comprehension gate

[know-code](https://kc.chtnnhfoundation.org) is an optional, **machine-local** layer on top of the shared hooks. It blocks `git commit` / `git push` until you pass a short quiz about the diff (useful when working with coding agents).

**Not enabled by default** — other contributors are unaffected.

### Opt in

```bash
npm i -g @chtnnh/know-code
know-code attest-init # once per machine
bash scripts/enable-know-code-hooks.sh
```

This copies `.husky/pre-commit.local.example` → `.husky/pre-commit.local` (and the pre-push variant). Those files are **gitignored**; only your machine runs `know-code check` after the shared `ci:pre-commit` / `ci:pre-push` scripts.

Manual setup instead of the script:

```bash
cp .husky/pre-commit.local.example .husky/pre-commit.local
cp .husky/pre-push.local.example .husky/pre-push.local
```

### Typical workflow (range mode)

One quiz covers the **entire feature batch**, not each commit.

1. `know-code range begin` at the start of a feature batch.
2. Land all commits (`git commit` runs shared `ci:pre-commit` only — know-code does **not** gate each commit).
3. When the batch is complete: agent teaches → you run `know-code taught`.
4. Agent writes `.know-code/quiz.json` from `know-code questions` → `know-code ask` → `know-code grade propose` → `know-code grade --review` → `know-code pass` (quiz covers the **full range diff**).
5. `know-code range seal` (adds verification trailer / receipt).
6. `git push` (shared `ci:pre-push` + know-code `check` on pre-push).

Use `know-code commit -m "…"` only if you prefer the CLI wrapper after `pass`; regular `git commit` is fine while building the range. See [kc.chtnnhfoundation.org](https://kc.chtnnhfoundation.org) for the tutorial.

**Hooks:** enable know-code on **pre-push only** (`.husky/pre-push.local`). Do not add know-code to pre-commit — that forces a quiz per commit and breaks range mode.

### Disable on this machine

```bash
rm .husky/pre-commit.local .husky/pre-push.local
```

Emergency bypass (human TTY): `know-code override`, then `KNOW_CODE_OVERRIDE=1 git commit`. Do not use in CI or agent shells.

## Viewing CI failure screenshots

1. Open the failed GitHub Actions run (**CI → test** or **CI → visual**).
2. Scroll to **Artifacts** at the bottom of the summary.
3. Download **`test-results-…`** for failure screenshots, visual diffs (`*-expected.png`, `*-actual.png`, `*-diff.png`), and `trace.zip`.
4. Download **`playwright-report-…`** and open `index.html` in a browser for the interactive report.

## DB schema changes

1. Edit `packages/db/src/schema.ts`
2. Run `pnpm db:generate`
3. Commit new SQL under `packages/db/drizzle/` **and** `packages/db/drizzle/meta/`

## Testing layers

| Layer | Command |
|-------|---------|
| Unit | `pnpm test:unit` or `pnpm ci:unit` |
| E2E | `pnpm --filter @together/web test` |
| Visual update | `pnpm --filter @together/web test:visual:update` (Docker) |
| Full CI parity | `pnpm ci:local` |

## Formatting

```bash
pnpm format # Biome write
pnpm lint # Biome check
```

## Coverage notes

- **Keyboard shortcuts (mobile):** desktop-only interaction; mobile coverage is `keyboard-shortcuts-mobile.spec.ts` (verifies `?` in chat does not open help).
- **OG / favicon:** covered by `og-image.spec.ts` (desktop API); no separate mobile layout.
- **Playback sync visual:** no distinct layout — covered by E2E two-client specs and unit playback math.
Loading
Loading