Files

7.2 KiB

Development and testing

Prerequisites

  • Node.js compatible with the lockfile/native better-sqlite3 build.
  • npm.
  • Playwright system/browser dependencies for browser-backed tests or runtime work.
  • No live account is required for unit, contract, route, or dashboard tests.

NodeNext imports use .js suffixes even when the source file is .ts. Vitest globals are disabled, so tests import describe, it, expect, and hooks explicitly.

Safe setup

npm ci
npm run build
npm test

Do not start npm run dev merely to verify a build. The repository .env and persisted database can make the process live-capable. Starting the backend, importing sessions, or toggling the bot to running requires explicit authorization and a confirmed dry-run/live intent.

If native SQLite bindings fail after a Node upgrade, distinguish pure TypeScript/unit results from database verification. Rebuild/install a compatible better-sqlite3; --ignore-scripts is not a valid database test environment.

Commands

Command Purpose
npm run build Compile server and production dashboard.
npm run build:server Run backend TypeScript compiler.
npm run dashboard:typecheck Type-check the React application.
npm run dashboard:build Build dashboard assets.
npm test Run the complete Vitest suite once.
npm run test:watch Watch tests during local development.
npm run test:coverage Run with coverage.
npm run docs:api Regenerate docs/api.md.
npm run docs:api:check Fail if generated API documentation is stale.
npm run mcp Start the stdio MCP adapter; requires an authorized running API.
npm run dev Start the live-capable backend watcher.
npm run dashboard:dev Start Vite, proxying API requests to port 3000.

Change workflow

  1. Read agents.md, docs/README.md, the routed topic docs, owning source, and focused tests.
  2. Inspect git status before editing. Preserve unrelated user changes and do not broadly stage a dirty worktree.
  3. Establish a baseline appropriate to the change. Code-changing tasks follow the repository test-first instructions; docs-only changes use documentation/link checks.
  4. Identify the source-of-truth boundary: config schema, migration, service, shared transport contract, route, or UI feature.
  5. Implement the smallest coherent behavior using dependency injection and single-purpose modules.
  6. Add behavior-focused tests for observable inputs, outputs, state transitions, and side effects.
  7. Update every affected document and regenerate API docs when the catalog changes.
  8. Run focused tests while iterating, then full required checks before publishing.
  9. Review the exact staged diff, commit only the coherent set, push, and verify branch/remote sync.

Engineering practices

Types and validation

  • No production any; use unknown, Zod, discriminated unions, or type guards.
  • Keep database/service-private types separate from transport contracts.
  • Parse at boundaries and pass trusted domain values inward.
  • Return explicit terminal/retryable/human-required results where callers must decide policy.

Service design

  • Constructor-inject external dependencies, clocks, fetchers, schedulers, and persistence seams.
  • Keep process-global coordination separate from account-scoped mutable state.
  • Prefer a small policy/service over another conditional in a composition root or route.
  • Preserve abort signals through queues, sleeps, and remote operations.

Logging

Use the injected Winston logger. Include stage, account context (through child loggers), post/conversation IDs, and safe rejection/retry reasons. Never serialize raw Axios/Playwright errors that may include cookies or authorization headers; extract a safe message/status. Avoid high-frequency unchanged status logs.

Remote effects

  • Check dry-run at the final side-effect boundary.
  • Make retries idempotent and distinguish remote acceptance from local persistence.
  • Reserve recipients/claims before sending and release only on safe failure paths.
  • Treat 403, 404, and 429 according to their typed domain meaning rather than one generic retry.

Test layout and patterns

Tests live in tests/; dashboard tests are under tests/dashboard/, route/event tests under tests/web/, and shared contract tests under packages/api-contracts/tests/.

Preferred patterns:

  • in-memory SQLite with real migrations/repositories;
  • fake clock/sleep/fetch functions injected into services;
  • small service fakes implementing narrow interfaces;
  • Testing Library for user-observable React behavior;
  • representative payload parsing for strict Zod contracts;
  • lifecycle/restart tests for queues, claims, and account runtimes.

Avoid deleting coverage to make a suite pass, assertions that pin private call order without behavioral value, ESM namespace mocking when injection is available, or tests that read the real .env/production data.

Verification matrix

Change Minimum focused verification Final verification
Pure backend/service owning Vitest files npm test, npm run build:server
Database/migration migration + repository tests full tests and server build
API/contract route + contract + auth tests; regenerate docs full tests, build, docs:api:check
Dashboard feature tests + typecheck full tests and full build
Docker/deployment compose/Docker tests + image build as appropriate health, API, container, logs, and persistence after authorized deploy
Documentation only generated-doc check + internal link scan staged diff review

If the worktree has pre-existing failures or concurrent changes, record the exact baseline and do not attribute them to your change. Never hide a failed required check behind a passing focused test.

Common implementation recipes

Add an endpoint

Create or extend a focused router, validate input, add shared output contracts, register metadata in api-catalog.ts, add authorization/behavior tests, consume via dashboard query helpers if needed, regenerate docs/api.md, and update the relevant narrative doc.

Add persisted state

Append a migration, add a narrow repository, wire it through the composition root/runtime, test fresh and restart/upgrade cases, and update database.md.

Change candidate or reply behavior

Start with the durable state transition and idempotency rule. Test rejection/retry/success, process interruption, account ownership, and operator-visible reason counts. Update product, flow, service, and data docs as applicable.

Add dashboard state

Define the shared schema first, add a typed query/mutation, keep route/filter state in the URL where useful, invalidate snapshots from relevant SSE events, and verify loading/error/stale/accessibility states.

  • npm run learning:eval -- --db <sqlite-path> --policy <version> runs the offline learning hard gates against eligible redacted decisions and persists a versioned evaluation result. Use a database backup or non-production copy when evaluating production-derived data. AI request logs contain prompt length and SHA-256 only. Do not restore full prompt logging: conversation prompts can contain private messages and retrieved learning context.