# CLAUDE.md Instructions for Claude Code working in this repository. --- ## Agent Behavior **Do NOT** run long-running processes without explicit permission: - `pnpm dev`, `pnpm dev:start`, `npm start`, `npm run dev` - Any command that starts servers, watchers, or blocking processes **Always ask first** before: - Starting development servers - Running Docker containers - Executing build watchers - Any process that won't terminate on its own **Before coding**: Read relevant docs. Never guess endpoint behavior or payload shapes. --- ## Quick Reference ```bash # Build domain (required after domain changes) pnpm domain:build # Type check & lint pnpm type-check pnpm lint # Database pnpm db:migrate pnpm db:generate # Tests pnpm test pnpm --filter @customer-portal/bff test ``` **Ports**: Frontend :3000 | Backend :4000/api | Prisma Studio :5555 --- ## Architecture ### Monorepo ``` apps/ ├── portal/ # Next.js 15 (React 19, Tailwind, shadcn/ui) └── bff/ # NestJS 11 (Prisma, BullMQ, Zod) packages/ └── domain/ # Shared contracts, schemas, provider mappers ``` ### Three-Layer Boundary | Layer | Location | Purpose | | ------ | ------------------ | -------------------------------------------------- | | Domain | `packages/domain/` | Contracts, Zod schemas, provider mappers | | BFF | `apps/bff/` | HTTP boundary, orchestration, integrations | | Portal | `apps/portal/` | UI layer, thin route wrappers over feature modules | ### Systems of Record - **WHMCS**: Billing, subscriptions, invoices, authoritative addresses - **Salesforce**: CRM (Accounts, Contacts, Cases), order snapshots - **Portal**: UI + BFF orchestration --- ## Import Rules (ESLint Enforced) ```typescript // Allowed (Portal + BFF) import type { Invoice } from "@customer-portal/domain/billing"; import { invoiceSchema } from "@customer-portal/domain/billing"; import { Formatting } from "@customer-portal/domain/toolkit"; // Allowed (BFF only) import { Whmcs } from "@customer-portal/domain/billing/providers"; // Forbidden everywhere import { Billing } from "@customer-portal/domain"; // root import import { Invoice } from "@customer-portal/domain/billing/contract"; // deep import // Forbidden in Portal import { Whmcs } from "@customer-portal/domain/billing/providers"; // provider adapters ``` --- ## Domain Package Each module follows: ``` packages/domain// ├── contract.ts # Normalized types (provider-agnostic) ├── schema.ts # Zod validation ├── index.ts # Public exports └── providers/ # Provider-specific (BFF-only) └── whmcs/ ├── raw.types.ts # Raw API response types └── mapper.ts # Transform raw → domain ``` **Key principle**: Map once in domain mappers, use domain types everywhere. --- ## Portal Structure ``` apps/portal/src/ ├── app/ # Next.js App Router (thin shells, NO API calls) ├── components/ # Atomic: atoms/ molecules/ organisms/ templates/ ├── core/ # Infrastructure: api/, logger/, providers/ ├── features/ # Feature modules (api/, stores/, hooks/, views/) └── shared/ # Cross-feature: hooks/, utils/, constants/ ``` ### Feature Module Pattern ``` features// ├── api/ # Data fetching (uses core/api/apiClient) ├── stores/ # Zustand state ├── hooks/ # React Query hooks ├── components/ # Feature UI ├── views/ # Page-level views └── index.ts # Public exports (barrel) ``` **Rules**: - Pages are thin wrappers importing views from features - No API calls in `app/` directory - No business logic in frontend; use services and APIs --- ## BFF Patterns ### Integration Layer ``` apps/bff/src/integrations/{provider}/ ├── services/ │ ├── {provider}-connection.service.ts │ └── {provider}-{entity}.service.ts └── utils/ └── {entity}-query-builder.ts ``` ### Data Flow ``` External API → Integration Service → Domain Mapper → Domain Type → Use Directly (fetch + query) (transform once) (return) ``` **Integration services**: 1. Build queries (SOQL, API params) 2. Execute API calls 3. Use domain mappers to transform 4. Return domain types 5. NO additional mapping or business logic ### Controllers - Thin: no business logic, no Zod imports - Use `createZodDto(schema)` + global `ZodValidationPipe` --- ## Validation (Zod-First) - Schemas in domain: `packages/domain//schema.ts` - Derive types: `export type X = z.infer` - Query params: use `z.coerce.*` for URL strings --- ## Code Standards - No `any` in public APIs - No `console.log` (use logger: `nestjs-pino` for BFF, `@/core/logger` for Portal) - Avoid `V2` suffix in service names - No unsafe assertions - Reuse existing types and functions; extend when needed --- ## Documentation Read before implementing: | 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/` |