Appearance
Authority Doc / Public V1 Toolchain
The Toolchain Contract defines how CoachMe code is installed, generated, validated, tested, built, and prepared for release.
This page is the Public V1 authority for development tools, package scripts, code generation, migrations, test commands, CI command shape, generated-file policy, dependency updates, mobile build tooling, and release-note tooling across the future CoachMe app monorepo.
AuthorityTypeScriptpnpm + TurboCodegenCIPublic V1
Note
This page does not define architecture rationale, environment secrets, REST semantics, privacy policy, observability, or final release approvals. It defines the toolchain used to produce implementation and release evidence.
Scope
This contract owns the baseline toolchain and stable command surface for the future CoachMe app monorepo, while adjacent authority pages own architecture, environment, API behavior, and release approvals.
This Contract Owns
- Runtime and package manager versions.
- Monorepo orchestration and workspace layout conventions.
- Root package scripts and CI command names.
- Lint, format, typecheck, package build, and local hook tools.
- API code generation tools and generated client placement.
- Database migration generation and application commands.
- Test runner choices for unit, integration, web E2E, and mobile E2E.
- Web, mobile, forms, styling, and client-cache toolchain defaults.
- Runtime configuration validation tooling.
- Generated-file commit policy.
- CI provider and command-level merge expectations.
- Dependency update automation and release-note tooling.
- Observability package installation, build integration, source-map upload paths, exact locks, and update policy.
This Contract Does Not Own
- Business architecture and bounded contexts, owned by technical-architecture-plan.
- Environment inventory, secrets, deployment topology, backup, restore, and rollback, owned by environment-runbook.
- REST route semantics, error envelopes, compatibility, and contract behavior, owned by api-contract-standard.
- Final release approvals, coverage thresholds, app-store smoke tests, and launch evidence, owned by the Test And Release Gate.
- Privacy, retention, incident handling, or security policy.
- Provider decisions outside the tools needed to generate, build, or test the app.
- Telemetry signal semantics, provider approval, topology, access grants, and retention owned by Observability, Integration, Environment, Roles, and Privacy.
Note
Secret detection and dependency-vulnerability checks are required by the Test And Release Gate. This contract owns their stable command surface and pinned scanner implementations.
Baseline
These toolchain decisions are locked for Public V1 so local development, generated contracts, CI, and release preparation all use the same foundation.
| Concern | Decision | Notes |
|---|---|---|
| Runtime | Node.js 24 LTS | Local, CI, and production build images should align. |
| Package manager | pnpm 10 | Use Corepack or equivalent pinning. |
| Monorepo | pnpm workspaces + Turborepo | Turbo coordinates root scripts, caching, and affected work. |
| Backend | NestJS modular monolith | Architecture rationale remains in the technical architecture plan. |
| Web | Next.js App Router | Coach web and admin operations surface. |
| Mobile | Two Expo apps | Coach mobile and client/personal mobile. |
| Database access | Drizzle ORM + drizzle-kit | SQL migrations are committed. |
| API validation | NestJS DTO classes + class-validator | OpenAPI generated through @nestjs/swagger. |
| OpenAPI clients | openapi-typescript + openapi-fetch | Generated clients live in packages/contracts. |
| Unit/integration tests | Vitest | Default test runner across API and shared packages. |
| Web E2E | Playwright | Coach web browser regression and smoke coverage. |
| Mobile E2E | Maestro | Default choice for Public V1, revisitable if Expo constraints require it. |
| CI | GitHub Actions | Required PR checks run the stable root commands. |
| Mobile release | EAS Build + EAS Submit + EAS Update | OTA updates constrained to compatible JS/runtime changes. |
| Formatting | Prettier | Formatting only. |
| Linting | ESLint flat config | Correctness and framework rules. |
| Env validation | Zod per app/package | Fail fast at startup and in CI. |
| Client server state | TanStack Query | Shared pattern across coach web and both mobile apps. |
| Forms | React Hook Form + Zod resolvers | Used for web and mobile forms. |
| Web styling | Tailwind CSS | Paired with shared design tokens. |
| Mobile styling | NativeWind | Paired with shared design tokens. |
| Web UI | shadcn/ui + Radix primitives | Wrapped in CoachMe-owned packages/ui-web. |
| Mobile UI | CoachMe-owned React Native primitives + NativeWind | Implemented in packages/ui-mobile. |
| Mobile navigation | Expo Router | Default for now, explicitly revisitable. |
| Git hooks | Husky + lint-staged | Changed-file format/lint only. |
| Dependency updates | Renovate | Grouped low-risk updates; deliberate Expo/React Native updates. |
| Release notes | Changesets | Publishing disabled unless later enabled. |
| Shared package builds | tsup + tsc --noEmit | tsup emits packages; TypeScript checks types. |
Observability Packages And Source Maps
This contract owns how the Observability-selected package families enter builds and stay compatible.
Observability package families
| Concern | Package family | Lock rule |
|---|---|---|
| Backend logging | pino and pino-http, integrated through CoachMe-owned Nest middleware. | Exact lockfile versions; default request serializers remain disabled by application configuration. |
| Metrics only | @opentelemetry/api, @opentelemetry/sdk-metrics, @opentelemetry/exporter-metrics-otlp-http, and @opentelemetry/resources. | Exact compatible versions shared by API and workers; no tracing SDK or client instrumentation at Launch. |
| Semantic conventions | @opentelemetry/semantic-conventions. | Pin one exact version shared by API/workers and record it with metric/query evidence. |
| Errors | @sentry/nestjs, @sentry/nextjs, and @sentry/react-native. | Exact compatible versions coordinated with framework and Expo releases. |
Backend And Web Symbolication
Generate and upload server source maps for one backend release; distinguish API and worker by runtime/service context. Upload Next.js server/client maps during staging/production builds and do not serve them publicly.
Mobile Symbolication
EAS/Sentry uploads bundle maps for coach mobile and client mobile with exact release/build/dist metadata. Local/test never upload. The upload token is a CI/build secret.
Note
A failed required source-map upload blocks staging/production promotion, while runtime Sentry unavailability remains non-blocking. Deliberate staging errors must symbolicate API, worker, coach web, coach mobile, and client mobile.
Monorepo Layout
The future app repository separates deployable applications from shared packages so build boundaries, generated contracts, and shared UI stay explicit.
Application Packages
apps/apifor the NestJS API, workers, OpenAPI generation, and Drizzle migrations.apps/webfor the Next.js coach and admin web app.apps/mobile-coachfor the Expo coach mobile app.apps/mobile-clientfor the Expo client/personal mobile app.
Shared Packages
packages/domainpackages/contractspackages/mobile-corepackages/ui-webpackages/ui-mobilepackages/design-tokenspackages/config
Note
Package boundaries should remain meaningful. Shared packages should not become dumping grounds for feature-specific behavior.
Package Scripts
Root scripts are the stable developer and CI interface. Package-local scripts can evolve underneath them without changing the contract surface.
| Script | Purpose |
|---|---|
pnpm dev | Run the main local development stack through Turbo. |
pnpm build | Build all buildable apps and packages. |
pnpm lint | Run ESLint. |
pnpm format | Run Prettier in write mode. |
pnpm format:check | Run Prettier in check mode. |
pnpm typecheck | Run TypeScript checks. |
pnpm test | Run Vitest. |
pnpm test:watch | Run Vitest in watch mode. |
pnpm test:e2e:web | Run Playwright web E2E and smoke tests. |
pnpm test:e2e:mobile | Run Maestro mobile E2E and smoke tests. |
pnpm codegen | Generate OpenAPI spec and clients. |
pnpm codegen:check | Fail if generated contracts drift. |
pnpm db:generate | Generate Drizzle SQL migrations. |
pnpm db:migrate | Apply Drizzle migrations. |
pnpm db:seed | Run the app seed script; seed/fixture policy is owned by the Environment Runbook and Test And Release Gate. |
pnpm db:studio | Run Drizzle Studio for local inspection only. |
pnpm env:check | Validate app and package environment schemas. |
pnpm security:secrets | Run the pinned Gitleaks configuration against the repository and relevant history. |
pnpm security:dependencies | Run pnpm audit --audit-level high through the repository wrapper and fail on high or critical findings. |
pnpm security:check | Run all required secret and dependency-vulnerability checks. |
pnpm verify | Run the CI-equivalent local gate. |
Note
The exact root script list can evolve, but root scripts remain the stable developer and CI interface. Package-local scripts are implementation details underneath this contract.
Code Quality
Formatting, linting, and local hooks stay fast and predictable so developers get quick feedback without moving CI-only work into pre-commit scripts.
- ESLint uses flat config.
- Prettier owns formatting.
lint-stagedruns changed-file formatting and lint checks through Husky.- Pre-commit hooks must stay fast and must not run full tests, builds, Docker services, Playwright, Maestro, or migrations.
- Heavy checks belong in
pnpm verifyand GitHub Actions.
Note
Stylelint is not part of the Public V1 baseline unless custom CSS grows enough to justify it.
TypeScript Builds
Package build rules keep shared code consumable across apps while preserving explicit boundaries between deployable surfaces and reusable packages.
- TypeScript strict mode is the default unless a package has a documented exception.
tsc --noEmitis the canonical typecheck.tsupbuilds shared packages that need emitted output.- Source-only packages are allowed only where the consuming framework requires it or where emitted output adds no value.
- Package exports are explicit.
- Shared packages must not import from apps.
- Apps import from shared packages through package names, not fragile relative paths.
Note
Build boundaries are part of architecture discipline, not only bundler housekeeping.
API Codegen
Generated contracts follow a fixed server-to-client path so DTO changes, OpenAPI output, and client packages move together and can be checked for drift.
1. Define DTOs
NestJS controllers and DTO classes are the server source for OpenAPI generation.
Source
2. Validate requests
Runtime request validation uses class-validator through NestJS validation pipes.
Validate
3. Generate OpenAPI
@nestjs/swagger generates the OpenAPI document from controllers and DTO metadata.
Spec
4. Generate clients
openapi-typescript generates TypeScript types and openapi-fetch provides the shared fetch client foundation.
Client
5. Check drift
pnpm codegen:check fails CI when generated clients or OpenAPI output drift from source.
Gate
Note
REST semantics, compatibility, response envelopes, and error envelopes are owned by api-contract-standard.
Database Migrations
Database schema changes flow through committed SQL migrations so local work, CI, and promoted environments use the same migration history.
| Concern | Rule |
|---|---|
| Access layer | Drizzle ORM is the database access layer. |
| Generate migration | pnpm db:generate runs drizzle-kit generate or the repo-equivalent wrapper. |
| Commit migration | Generated SQL migrations are committed. |
| Apply migration | pnpm db:migrate applies migrations. |
| Local inspection | pnpm db:studio runs Drizzle Studio for local inspection only. |
| Prototype shortcut | push is allowed only for disposable local prototyping and never for CI, staging, or production. |
Note
Seed and fixture policy belongs primarily to environment-runbook and the Test And Release Gate; this page owns the command names.
Testing
Runner ownership is fixed here so each test type has a clear default tool and adjacent authority pages can own the deeper protocol and release-gate requirements.
| Test Area | Rule |
|---|---|
| Unit and integration | Vitest owns unit tests and most integration tests for backend and shared packages. |
| API integration | API integration tests can use PostgreSQL, Redis, MinIO, Keycloak test fixtures, and worker processes where required. |
| Web E2E | Playwright owns coach web browser smoke and E2E tests. |
| Mobile E2E | Maestro owns mobile smoke and E2E flows for coach mobile and client mobile. |
| Contract tests | Contract tests compare generated clients, OpenAPI output, and representative API behavior. |
| Offline sync | Offline sync tests follow offline-sync-protocol. |
| Events and outbox | Event and outbox tests follow event-and-outbox-standard. |
| Release gate | Final coverage, release smoke matrix, accessibility checks, RTL checks, and launch blockers belong to the Test And Release Gate. |
Web Toolchain
The coach web stack uses a consistent set of framework, styling, data, and form tools so page models, interactive state, and shared UI stay aligned.
- Next.js App Router is the coach web foundation.
- Tailwind CSS is the web styling baseline.
- shadcn/ui and Radix primitives are copied or wrapped into
packages/ui-web. - Shared design tokens feed Tailwind configuration.
- TanStack Query owns interactive client-side server state.
- Next.js Server Components may fetch directly for page-level read models where that is cleaner.
- React Hook Form + Zod resolvers own web form state and validation.
- Playwright owns browser E2E and smoke tests.
Note
UI design rules belong in product and design docs. This page owns the technical toolchain.
Mobile Toolchain
The mobile stack keeps the two Expo apps aligned on shared primitives, shared infrastructure, and one release toolchain while leaving app-specific UI and flows to the applications.
Apps and Shared UI
- Coach mobile lives in
apps/mobile-coach. - Client and personal mobile lives in
apps/mobile-client. - NativeWind and shared design tokens are the mobile styling baseline.
- CoachMe-owned
packages/ui-mobileis built from React Native primitives and NativeWind. - Expo Router is the default navigation layer for now.
- TanStack Query owns mobile server state.
- React Hook Form + Zod resolvers own mobile form state and validation.
Shared Core and Delivery
packages/mobile-coreowns shared auth/session, API client setup, sync helpers, push helpers, localization/RTL helpers, and secure local integration wrappers.- Maestro is the default mobile E2E runner.
- EAS Build, EAS Submit, and EAS Update are the mobile build and release toolchain.
Note
EAS Update can ship compatible JavaScript/runtime fixes. It must not be used for native dependency changes, permission changes, schema changes, contract-breaking changes, or changes that require a new binary.
Configuration Validation
Environment validation is a build and startup concern, not an optional runtime convention, so every consumer that reads configuration must prove its schema.
- Each app or package that reads environment variables has a Zod schema.
pnpm env:checkvalidates required environment schemas.- Startup fails fast when required runtime configuration is invalid.
- Mobile build profiles validate public runtime config before EAS build.
- The Environment Runbook owns the variable inventory and per-environment values.
- The Toolchain Contract owns the validation pattern and script gate.
Generated Files
Committed generated assets are limited to files that form part of the contract or migration history, while build outputs and test artifacts stay disposable.
| Policy | Rule |
|---|---|
| Commit | OpenAPI clients in packages/contracts when needed by consumers and CI drift checks. |
| Commit | Drizzle SQL migrations. |
| Do not commit | .next, dist, coverage output, Turbo cache, Expo build artifacts, and Playwright or Maestro test artifacts. |
| Exception | A release process may later define a committed artifact bundle, but this contract does not require one for Public V1 planning. |
| Gate | CI fails when committed generated files do not match source. |
CI And Merge
Merge readiness depends on stable root commands, with GitHub Actions enforcing the contract and the Test And Release Gate defining deeper thresholds and evidence.
- Install dependencies with pnpm 10 and cache pnpm/Turbo appropriately.
- Run
pnpm format:check. - Run
pnpm lint. - Run
pnpm typecheck. - Run
pnpm test. - Run
pnpm codegen:check. - Run
pnpm security:check. - Run migration checks when database code changes.
- Run
pnpm build. - Run Playwright smoke coverage once coach web flows exist.
- Run Maestro smoke coverage once mobile apps and test flows exist.
Note
Exact required checks, thresholds, release-candidate gates, and app-store smoke evidence belong to the Test And Release Gate.
Updates And Releases
Dependency automation and release-note tooling are fixed at the contract level so routine updates and release communication follow one documented path.
Renovate
Renovate is the dependency update tool. Low-risk dev tooling updates can be grouped, major updates are separate, and Expo, React Native, EAS, mobile native dependencies, and framework major upgrades are reviewed deliberately.
Changesets
Changesets records release-note intent for app and package changes. Package publishing is disabled unless CoachMe later decides to publish shared packages.
Observability SDK Updates
Pino, Sentry, OpenTelemetry SDK major changes, and semantic-convention changes use separate Renovate changes. Re-run redaction, metric/query compatibility, startup, exporter, and source-map evidence. Updates cannot silently enable client OTel, Sentry logs, tracing, replay, profiling, screenshots, or performance tracing.
Release Notes
App release notes can be generated from changesets and release metadata once release automation exists.
Revisitable Decisions
This section separates defaults that can change with documented rationale from baseline choices that require a formal contract update before they move.
Revisitable With Recorded Rationale
- Mobile E2E: Maestro remains the default unless Expo or EAS constraints make it impractical, in which case a replacement can be adopted through a documented toolchain update.
- Mobile navigation: Expo Router remains the default unless direct React Navigation becomes the cleaner implementation choice for the mobile apps.
- The exact root script list can evolve while root scripts stay the stable developer and CI contract.
- Security scanner implementation may change through a documented Toolchain update while
pnpm security:secrets,pnpm security:dependencies, andpnpm security:checkremain the stable command contract.
Non-Revisitable Without Formal Contract Update
- Node.js 24 LTS + pnpm 10 stay locked as the baseline runtime and package manager pair.
- pnpm workspaces + Turborepo stay locked as the monorepo orchestration model.
- Drizzle ORM + drizzle-kit stay locked for schema access and migration generation.
- NestJS DTOs + class-validator + @nestjs/swagger stay locked for request validation and OpenAPI generation.
- openapi-typescript + openapi-fetch stay locked for generated API clients.
- Vitest + Playwright stay locked for unit, integration, and web E2E coverage.
- GitHub Actions stays locked as the CI provider.
- EAS Build + EAS Submit + EAS Update stay locked for mobile release flows.
- Tailwind CSS + NativeWind + shared design tokens stay locked for styling foundations.
- shadcn/ui + Radix primitives stay locked for web UI primitives.
- CoachMe-owned mobile UI package stays locked for mobile UI ownership.
- TanStack Query stays locked for client server-state management.
- React Hook Form + Zod stay locked for form composition and validation.
- Zod env validation stays locked for runtime configuration checks.
- Husky + lint-staged stay locked for local changed-file hooks.
- Renovate stays locked for dependency update automation.
- Changesets stays locked for release-note workflow.
- tsup + tsc --noEmit stay locked for shared package builds and type validation.
Related Docs
These documents own adjacent behavior, platform policy, and authority details that this toolchain contract references but does not redefine.
Workflow State Map
Cross-system workflow states and transitions.
Roles And Permissions
Role model and access boundaries.
API Contract Standard
REST semantics, error envelopes, and compatibility rules.
Event And Outbox Standard
Event publication, outbox handling, and integration guarantees.
Offline Sync Protocol
Sync behavior, conflict handling, and offline expectations.
Environment Runbook
Environment inventory, variables, and runtime operations.
Observability Plan
Owns signal semantics; this contract owns package, build, source-map, version-lock, and update mechanics.
Test And Release Gate
Release evidence, thresholds, and final approval gates.
Technical Architecture Plan
Architecture rationale and system decomposition.
Public V1 Scope Contract
Scope boundaries for the initial public product slice.