# Plan 003: Add Convex backend test harness and critical path coverage

> **Drift check**:
> `git diff --stat 74051ba..HEAD -- packages/backend`

## Status

- **Priority**: P1
- **Effort**: L
- **Risk**: LOW (adding tests)
- **Depends on**: ideally 001–002 so tests lock the real security/transition rules
- **Category**: tests
- **Planned at**: commit `74051ba`, 2026-07-09

## Why this matters

`packages/backend` has **no** `test` script and no `*.test.*`. Web Vitest mocks
`useMutation` (`apps/web/src/test/convex-mocks.ts`) so CI can be green while
server handlers regress. Domain pure tests in `packages/shared` do not cover
orchestration (auth actor, notify schedule, provision partial failure, publish
gates).

## Current state

- `packages/backend/package.json` scripts: only `dev`, `typecheck`.
- Critical untested: `deliveries.*` transitions, `users.inviteInternal` /
  `resetPassword`, `companies.create`, `nps.recordNps`, auth triggers.
- Root `bun run test` → turbo — backend contributes nothing today.
- Exemplar pure tests: `packages/shared/src/domain.test.ts`.
- Web seam policy documented in `apps/web/src/test/convex-mocks.ts`.

## Commands

| Purpose | Command | Expected |
|---------|---------|----------|
| Backend tests | `cd packages/backend && bun run test` | all pass (after script added) |
| Monorepo | `bun run test` | includes backend |
| Typecheck | `cd packages/backend && bun run typecheck` | exit 0 |

## Steps

### 1. Introduce harness

- Add `convex-test` (or current Convex-recommended unit test approach for this
  Convex version — **verify against Convex docs for 1.42** before pinning).
- Add `vitest` + `test` script to `packages/backend/package.json`.
- Ensure turbo `test` task picks it up (default pipeline should if script exists).

### 2. Seed fixture for tests

Reuse domain slugs from seed (`u_master`, `c_aurora`, …) or minimal insert
helpers. Do **not** call production seed action with real Resend.

### 3. Priority cases (minimum bar)

1. Unauthenticated `accept` / `resetPassword` denied (if 001 landed).
2. `publish` without pdf/link no-ops or throws (match current product behavior).
3. Illegal status transition denied (if 002 landed).
4. `submitRequest` without auth fails; with portal user writes correct companyId.
5. `recordNps` idempotency when `feedback.done` already true.
6. `requireAnalyst` rejects portal user slug.

### 4. Document boundary

Short note in `packages/backend/README` or root AGENTS: web tests = client seam;
backend tests = server truth.

## Out of scope

- Full invite email Resend E2E against real network
- Maestro mobile E2E
- 100% handler coverage

## STOP conditions

- If `convex-test` incompatible with `@convex-dev/better-auth` component layout —
  stop and report alternative (e.g. extract pure handlers).
- Do not weaken production auth to make tests pass.

## Done criteria

- [ ] `bun run test` from root runs backend suite.
- [ ] ≥6 high-value server tests green.
- [ ] CI (when present) would catch a deliberately broken `accept` precondition.

## Maintenance

New public mutation PR checklist: backend test or explicit waiver in PR body.
