# AGENTS.md

This is a pnpm workspace managed by Turborepo containing several deployable apps and shared internal packages.

## Project

Stack: pnpm workspaces, Turborepo, TypeScript, React, ESLint, Vitest.

```
apps/
  web/          public marketing site and app shell
  admin/        internal admin dashboard
  api/          HTTP service, deployed separately
packages/
  ui/           shared React components, no app imports
  core/         domain types and pure business logic
  db/           schema, client, and query helpers
  config/       shared eslint, tsconfig, and tailwind presets
```

Every package is private except where `publishConfig` says otherwise. Package names use the `@repo/` prefix.

Entry points: `turbo.json` (task graph), `pnpm-workspace.yaml` (package discovery), `packages/config/` (every shared preset).

## Architecture

Dependency direction is one way and enforced in review:

```
apps/*  ->  packages/ui, packages/core, packages/db
packages/ui   ->  packages/core
packages/db   ->  packages/core
packages/core ->  nothing internal
```

Rules that follow from this:

- A package in `packages/` never imports from `apps/`.
- `packages/core` has no React, no database driver, and no runtime environment assumptions.
- Cross app imports are forbidden. If `admin` needs something from `web`, it moves to a package.
- Shared code is added to an existing package before a new package is created. Ask before adding a package.
- Internal packages are consumed from TypeScript source, not from a build artifact.

## Commands

Use pnpm at the workspace root.

```bash
pnpm install                        # install the whole workspace
pnpm dev                            # turbo run dev across apps
pnpm build                          # turbo run build, respects the task graph
pnpm lint
pnpm typecheck
pnpm test

pnpm --filter @repo/ui build        # one package
pnpm --filter web dev               # one app
pnpm --filter @repo/core test       # one package's tests
pnpm --filter web add zod           # add a dependency to one package only
turbo run build --filter=web...     # a package and everything it depends on
```

Turbo caches task output. If a task reports success instantly it may be cached, use `--force` when verifying a fix.

Never run `pnpm add` at the root for a dependency that belongs to one package.

## Code style

- Each package exports through its `src/index.ts`. Deep imports into another package's internals are not allowed.
- `packages/ui` components take props only. No data fetching, no environment variables, no router imports.
- Shared packages have no top level side effects, importing them must be free.
- Types shared across packages live in `packages/core`, not duplicated per app.
- Extend the presets in `packages/config` rather than adding a local eslint or tsconfig rule.
- Keep one version of React, TypeScript, and every shared runtime dependency across the workspace.
- No default exports in shared packages, named exports keep refactors mechanical.

## Boundaries

Do not touch without explicit instruction:

- `turbo.json`, root `package.json`, `pnpm-workspace.yaml`.
- `pnpm-lock.yaml`. Use `pnpm --filter <pkg> add` and let it update.
- `packages/config/` presets, they change behavior for every package at once.
- `.github/workflows/` and any deploy configuration.
- Package `name`, `version`, or `exports` fields.

Needs human review: adding a new package, adding a dependency between packages, upgrading a shared runtime dependency, and anything that changes the public surface of `packages/core`.

## Testing

- `pnpm test` runs everything, `pnpm --filter @repo/core test` runs one package.
- `packages/core` and `packages/db` require tests for every exported function.
- `packages/ui` requires tests only for components with logic, not for layout wrappers.
- Apps require tests for route handlers and any code that is not a thin composition of packages.
- When changing a shared package, run the tests of every consumer: `turbo run test --filter=...@repo/core`.

## Git workflow

- Branch from `main`: `feat/short-description`, `fix/short-description`.
- Conventional commits with the package as scope: `fix(ui): correct focus ring on icon button`.
- A commit that touches several packages is fine when it is one logical change, otherwise split it.
- Any change to a package that is published requires a changeset: `pnpm changeset`.
- PR description lists which packages changed and whether consumers need updating.
- Never push to `main`.
