# Build, test, and quality gates

> Operations: Rust checks, clippy, SQLx preparation, TypeScript checks, Biome, Tailwind hygiene, Vitest, Playwright, and CI path filters.

- Repository: macro-inc/macro
- GitHub: https://github.com/macro-inc/macro
- Human docs: https://grok-wiki.com/public/docs/macro-inc-macro-bb988e1a448e
- Complete Markdown: https://grok-wiki.com/public/docs/macro-inc-macro-bb988e1a448e/llms-full.txt

## Source Files

- `justfile`
- `rust/cloud-storage/justfile`
- `js/package.json`
- `js/app/package.json`
- `js/app/justfile`
- `.github/workflows/code-check-cloud-storage.yml`
- `.github/workflows/web-app-check-main.yml`

---

---
title: "Build, test, and quality gates"
description: "Operations: Rust checks, clippy, SQLx preparation, TypeScript checks, Biome, Tailwind hygiene, Vitest, Playwright, and CI path filters."
---

The repository splits operational checks between `rust/cloud-storage` and `js/app`: Rust uses `just` recipes around Cargo, SQLx, and Nextest, while the web app uses Bun scripts, Biome, Vitest, Playwright, and GitHub Actions path filters to keep PR checks scoped.

## Command map

| Surface | Working directory | Command | Purpose |
|---|---:|---|---|
| Rust type check | `rust/cloud-storage` | `just check` | Runs `cargo check` with warnings denied and `SQLX_OFFLINE=true`. |
| Rust lint | `rust/cloud-storage` | `just clippy` | Runs workspace Clippy with all features, warnings denied, and `clippy::disallowed_methods` denied. |
| Rust format | `rust/cloud-storage` | `just format` | Runs `cargo fmt`; CI uses `cargo fmt --check`. |
| SQLx cache | `rust/cloud-storage` | `just prepare_db` | Runs workspace `cargo sqlx prepare --workspace -- --all-features`. |
| Rust tests | `rust/cloud-storage` | `cargo nextest run --all-features --lib --bins --tests` | Mirrors the CI test runner after database setup. |
| Web type check | `js/app` | `bun run type-check` | Runs `tsc --noEmit --skipLibCheck --project packages/app/tsconfig.json`. |
| Web combined check | `js/app` | `bun run check` | Runs type-check and `bun biome check`. |
| Web Biome CI | `js/app` | `bunx --bun biome ci --changed --no-errors-on-unmatched --error-on-warnings` | Matches the main web PR Biome gate. |
| Tailwind hygiene | `js/app` | `just check-tailwind` | Scans changed lines for prohibited raw Tailwind color/font utilities. |
| Vitest | `js/app` | `bunx vitest` or `bun run test` | Runs configured Vitest projects. |
| Local Playwright E2E | repository root | `just local-e2e` | Starts local dependencies, seeds deterministic data, then runs Playwright with `LOCAL_E2E=true`. |

<Note>
The JavaScript workspace declares `bun@1.3.5`. Rust uses the checked-in toolchain file with Rust `1.94.0` plus `clippy`, `rustfmt`, `rust-analyzer`, and `rust-src`.
</Note>

## Recommended pre-PR gate

<Steps>
  <Step title="Run Rust gates after Rust changes">
    ```bash
    cd rust/cloud-storage
    just check
    just clippy
    just format
    ```
  </Step>

  <Step title="Refresh SQLx metadata after SQL changes">
    ```bash
    cd rust/cloud-storage
    just prepare_db
    ```
    Commit any changed `.sqlx/query-*.json` files generated by SQLx.
  </Step>

  <Step title="Run web gates after TypeScript or UI changes">
    ```bash
    cd js/app
    bun run type-check
    bunx --bun biome ci --changed --no-errors-on-unmatched --error-on-warnings
    just check-tailwind
    bunx vitest
    bun run build
    ```
  </Step>

  <Step title="Run local E2E when behavior crosses the app/backend boundary">
    ```bash
    just local-e2e
    ```
  </Step>
</Steps>

## Rust cloud-storage gates

### Local checks

`rust/cloud-storage/justfile` owns the local Rust quality recipes:

```bash
just check
just clippy
just format
just build
```

`just check` sets `RUSTFLAGS=-Dwarnings`, `RUSTDOCFLAGS=-Dwarnings`, `CARGO_TERM_COLOR=always`, and `SQLX_OFFLINE=true` before `cargo check`.

`just clippy` applies the same warning policy and additionally denies `clippy::disallowed_methods`, then runs:

```bash
cargo clippy --workspace --all-features
```

`just format` runs `cargo fmt`. Use CI-style format checking with:

```bash
cargo fmt --check
```

### SQLx preparation

`rust/cloud-storage/sqlx.just` defines the database lifecycle wrappers. The default local database URL comes from `rust/cloud-storage/database.just`:

```text
postgres://user:password@localhost:5432/macrodb
```

The SQLx preparation recipe is workspace-level:

```bash
cd rust/cloud-storage
just prepare_db
```

It expands to:

```bash
cargo sqlx prepare --workspace -- --all-features
```

Use this after adding or changing SQLx compile-time checked queries, migrations that affect queried schemas, or Rust test queries that require refreshed offline metadata.

<Warning>
Do not hand-edit `.sqlx/query-*.json` files. Generate them with `just prepare_db` from `rust/cloud-storage`.
</Warning>

### Rust test database setup

The Rust test path uses live Postgres, not SQLx offline mode. The CI workflow starts `pgvector/pgvector:pg16` and Redis, configures Postgres for high-concurrency tests, then runs:

```bash
just rust/cloud-storage/setup_test_envs
just rust/cloud-storage/initialize_dbs
cd rust/cloud-storage
cargo nextest run --all-features --lib --bins --tests --test-threads 32
```

`setup_test_envs` writes `DATABASE_URL` into the crate-level `.env` files needed by SQLx-backed tests. `initialize_dbs` runs the macro database create/migrate setup.

<Warning>
Do not run Rust tests with `SQLX_OFFLINE=true`. Offline mode is for `cargo check`, `cargo build`, and `cargo clippy`; tests validate against the live local schema.
</Warning>

## Web app gates

### TypeScript

The web app TypeScript gate runs against `packages/app/tsconfig.json`:

```bash
cd js/app
bun run type-check
```

The top-level `js/package.json` also exposes:

```bash
cd js
bun run check
```

That delegates to the app type-check command.

In CI, the TypeScript job runs when either web files changed or Rust API inputs changed. If Rust API inputs changed, the job first runs generated client validation:

```bash
cd js/app
bun run gen-api -- --check
```

The generator builds Rust OpenAPI binaries with `SQLX_OFFLINE=true`, runs them, regenerates TypeScript clients through Orval, runs Biome over generated service clients, then fails in `--check` mode if `git diff` or untracked generated files remain.

### Biome

`js/app/biome.jsonc` configures Biome with Git VCS support, `origin/main` as the default branch, LF line endings, 2-space indentation, 80-column formatting, Solid rules enabled, React rules disabled, and generated-output exclusions.

CI runs:

```bash
cd js/app
biome ci --changed --no-errors-on-unmatched --error-on-warnings
```

Local equivalents include:

```bash
cd js/app
bunx --bun biome lint --skip=suspicious/noImportCycles
bunx --bun biome format --write
bunx --bun biome check --write
```

The web CI also has a separate import-cycle gate:

```bash
cd js/app
biome lint --changed --no-errors-on-unmatched --only=suspicious/noImportCycles
```

### Tailwind hygiene

`js/app/scripts/check-tailwind.ts` enforces theme hygiene on changed lines only. It scans changed `.tsx`, `.ts`, `.jsx`, and `.js` files under `packages/` and rejects raw utility classes matching:

- raw color utilities such as `bg-red-500`, `text-gray-700`, `border-black`, `fill-blue-400`
- raw `white` / `black` color utilities for the checked utility groups
- `font-berkeley` and `font-inter`

Run it with:

```bash
cd js/app
just check-tailwind
```

In CI, the base branch is `origin/${GITHUB_BASE_REF}`. Locally, the script defaults to `origin/dev`.

Expected success output includes:

```text
✅ No prohibited Tailwind classes found in changed lines!
```

On failure, the script prints file, line, column, matched class name, and a hint to replace raw utilities with semantic classes.

### Vitest

`js/app/vitest.config.ts` defines a multi-project Vitest setup for package groups including `websocket`, `core`, `queries`, `scripts`, `lexical-core`, `theme`, `block-channel`, `channel`, `notifications`, and `block-email`.

Run once:

```bash
cd js/app
bunx vitest
```

Run via package script:

```bash
cd js/app
bun run test
```

Watch mode is exposed through the app justfile:

```bash
cd js/app
just test-watch
```

The web PR workflow installs Bun dependencies with `bun install --frozen-lockfile`, installs/caches Playwright Chromium when requested by the setup action, then runs `bunx vitest`.

### Build

The app build script is:

```bash
cd js/app
bun run build
```

It runs from `packages/app` with:

```bash
MODE=development NODE_ENV=production bun run --bun build
```

The app justfile also provides mode-specific builds:

```bash
just build-dev
just build-staging
just build-prod
just build-tauri
```

## Playwright and local E2E

Playwright is configured in `js/app/playwright.config.ts` with `testDir: ./tests/e2e`, fully parallel execution, trace retention on failure, and `baseURL` set to `http://localhost:${PORT:-3000}/app`.

The repository-level local E2E harness is the safest entry point:

```bash
just local-e2e
```

It performs the full setup:

1. starts LocalStack with test AWS credentials,
2. starts the local service subset through Docker Compose,
3. seeds deterministic E2E data,
4. runs `LOCAL_E2E=true bunx playwright test` in `js/app`.

For UI mode:

```bash
just local-e2e-ui
```

`LOCAL_E2E=true` changes Playwright to a single `local-chromium` project and generates a local JWT unless `LOCAL_JWT` is already exported. Direct Playwright runs can fail token generation if `.env` and seeded local data are missing; prefer the repo-level harness.

## CI path filters

### Cloud Storage PR check

`.github/workflows/code-check-cloud-storage.yml` runs on pull requests to `main` for opened, synchronized, reopened, and ready-for-review events. The path filter enables the workflow for changes under:

- `rust/cloud-storage/**`
- `rust/rust-toolchain.toml`
- `flake.nix`
- `flake.lock`
- cloud-storage CI workflow and supporting GitHub actions/scripts

The workflow has three effective stages:

| Job | Runs when | Gate |
|---|---|---|
| `path-check` | Always on matching PR event | Computes `should_run` and an optional Nextest package filter. |
| `check` | `should_run == true` and PR is not draft | Runs Rust format check and Clippy. |
| `test` | `should_run == true` and PR is not draft | Starts Postgres/Redis, initializes DBs, and runs Nextest. |
| `status-check` | Always | Fails only if `path-check`, `check`, or `test` failed. Skipped jobs are accepted. |

For package-specific Rust changes, CI computes a Nextest expression such as:

```text
rdeps(=package_name)
```

Multiple package filters are joined with `|`. Workspace-level changes, lockfiles, toolchain changes, Cargo workspace changes, or CI/action changes force the full test suite.

### Web app PR check

`.github/workflows/web-app-check-main.yml` runs on pull requests to `main`. Its path filters produce two outputs:

| Output | Matching changes |
|---|---|
| `should_run` | Web package files, app packages/src, `biome.jsonc`, lexical workspaces, setup actions, and the workflow file. |
| `api_changed` | Rust cloud-storage Rust/Cargo files, flake files, API generation scripts, setup actions, and the workflow file. |

The jobs are scoped as follows:

| Job | Condition | Command |
|---|---|---|
| `typescript` | `should_run == true` or `api_changed == true` | Optionally `bun run gen-api -- --check`, then `tsc`. |
| `biome-check` | `should_run == true` | `biome ci --changed --no-errors-on-unmatched --error-on-warnings`. |
| `tailwind` | `should_run == true` | `just check-tailwind`. |
| `test` | `should_run == true` | `bunx vitest`. |
| `cycles` | `should_run == true` | Biome changed-file import-cycle lint. |
| `build` | `should_run == true` | `bun run build`. |
| `status-check` | Always | Fails only if a needed job failed. Skipped jobs are accepted. |

This means a Rust API-only change can trigger the TypeScript/API generation validation without running every web-only gate.

## Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| SQLx reports missing cached query data during check/build | `.sqlx` metadata is stale or absent | Run `cd rust/cloud-storage && just prepare_db`. |
| Rust tests fail when `SQLX_OFFLINE=true` is set | Tests need a live schema | Unset `SQLX_OFFLINE`, initialize DBs, and rerun tests. |
| Web TypeScript CI fails after Rust API changes | Generated service clients are out of sync | Run `cd js/app && bun run gen-api`, review generated files, commit updates. |
| Tailwind hygiene fails on new classes | Raw color/font utilities were added on changed lines | Replace with semantic theme classes. |
| Direct Playwright run cannot generate `LOCAL_JWT` | Local seed/env prerequisites are missing | Run `just local-e2e` or export `LOCAL_JWT` after preparing local data. |
| Biome changed-file CI finds no files locally | Wrong comparison branch | Fetch the expected base branch and rerun from `js/app`. |

## Next

For backend database work, pair this page with the repository’s SQLx migration and query-update conventions. For UI changes, run the web gates before opening a PR and use `just local-e2e` when the change depends on local services.
