# CLAUDE.md ## Agent Behavior **Always use `pnpm`** — never `npm`, `yarn`, or `npx`. Use `pnpm exec` for local binaries, `pnpm dlx` for one-off execution. **Never run long-running processes** (dev servers, watchers, Docker) without explicit permission. **Read relevant docs before implementing** — never guess endpoint behavior or payload shapes. **Use dedicated tools, not Bash** — Read (not `cat`/`head`/`tail`), Glob (not `find`/`ls`), Grep (not `grep`/`rg`), Edit (not `sed`/`awk`). This applies to all agents and subagents. **Never run destructive git commands** — `git stash`, `git checkout -- .`, `git restore .`, `git reset --hard`, `git clean`, or any command that discards uncommitted work. If you need to check pre-existing state, use `git diff` or `git status` — never stash or discard the working tree. ## Commands ```bash pnpm domain:build # Required after domain changes pnpm type-check pnpm lint pnpm db:migrate pnpm db:generate pnpm test # All tests pnpm --filter @customer-portal/bff test # BFF tests only ``` Ports: Frontend :3000 | Backend :4000/api | Prisma Studio :5555 ## Architecture ``` apps/ ├── portal/ # Next.js 15 (React 19, Tailwind, shadcn/ui) └── bff/ # NestJS 11 (Prisma, BullMQ, Zod) packages/ └── domain/ # Shared contracts, Zod schemas, provider mappers ``` **Systems of record**: WHMCS (billing, subscriptions, invoices, addresses) | Salesforce (CRM, orders) | Portal (UI + BFF orchestration) ## Key Conventions **Imports** (ESLint enforced): - Import from module index: `@customer-portal/domain/billing` — never root or deep paths - Provider imports (`/providers`) are BFF-only, forbidden in Portal **Domain**: Each module has `contract.ts`, `schema.ts`, `index.ts`, and `providers/` (BFF-only mappers). Map once in mappers, use domain types everywhere. **Portal**: Pages in `app/` are thin shells — all logic lives in `features/` modules. No API calls in `app/`. Use `@/core/logger` not `console.log`. **BFF**: Integration services fetch, transform via domain mappers, return domain types. Controllers are thin — use `createZodDto(schema)` + `ZodValidationPipe`. Use `nestjs-pino` logger not `console.log`. **Validation**: Zod-first. Schemas in domain, derive types with `z.infer`. Use `z.coerce.*` for query params. ## Docs | Topic | Location | | ------------------- | ---------------------------------------------- | | Overview | `docs/README.md` | | BFF patterns | `docs/development/bff/integration-patterns.md` | | Portal architecture | `docs/development/portal/architecture.md` | | Domain structure | `docs/development/domain/structure.md` | | Salesforce | `docs/integrations/salesforce/` | | WHMCS | `docs/integrations/whmcs/` |