## Customer Portal - AI Coding Rules (Focused)

These rules are the fast “guardrails” for AI agents in this repo. Detailed patterns live in docs; when unsure, read them first.

### Read before coding

- `docs/README.md` (entrypoint)
- `docs/development/` (BFF/Portal/Domain patterns)
- `docs/architecture/` (boundaries)
- `docs/integrations/` (external API details)

Rule: **Never guess** endpoint behavior or payload shapes. Find docs or an existing implementation first.

### Repo boundaries (non-negotiable)

- **Domain (`packages/domain/`)**: shared contracts + Zod validation + cross-app utilities. Framework-agnostic.
- **BFF (`apps/bff/`)**: NestJS HTTP boundary + orchestration + integrations (Salesforce/WHMCS/Freebit).
- **Portal (`apps/portal/`)**: Next.js UI; pages are thin wrappers over feature modules.

### Import rules (enforced by ESLint)

- **Allowed (Portal + BFF)**:
  - `@customer-portal/domain/<module>`
  - `@customer-portal/domain/toolkit`
- **Allowed (BFF only)**:
  - `@customer-portal/domain/<module>/providers`
- **Forbidden everywhere**:
  - `@customer-portal/domain` (root import)
  - any deep import like `@customer-portal/domain/<module>/**`
  - any deep import like `@customer-portal/domain/<module>/providers/**`
- **Forbidden in Portal**:
  - `@customer-portal/domain/*/providers` (Portal must never import provider adapters)

Examples:

```ts
// ✅ correct (apps)
import type { Invoice } from "@customer-portal/domain/billing";
import { invoiceSchema } from "@customer-portal/domain/billing";

// ✅ correct (BFF integrations only)
import { Whmcs } from "@customer-portal/domain/billing/providers";

// ❌ forbidden
import { Billing } from "@customer-portal/domain";
import { Invoice } from "@customer-portal/domain/billing/contract";
import { transformWhmcsInvoice } from "@customer-portal/domain/billing/providers/whmcs/mapper";
```

### Validation rules (Zod-first)

- **Schemas live in domain**: `packages/domain/<module>/schema.ts`
- **Derive types from schemas**: `export type X = z.infer<typeof xSchema>`
- **Query params**: use `z.coerce.*` for URL strings.

### BFF rules (NestJS)

- **Controllers are thin**:
  - no business logic
  - no `zod` imports in controllers
  - use `createZodDto(schema)` + global `ZodValidationPipe`
- **Integrations are thin**:
  - build queries in `apps/bff/src/integrations/<provider>/utils`
  - fetch data
  - transform once via domain mappers
  - return domain types
- **Errors**:
  - never leak sensitive details to clients
  - log details server-side, return generic user messages

### Portal rules (Next.js)

- **Pages are wrappers** under `apps/portal/src/app/**` (no API calls in pages)
- **Feature modules own logic** under `apps/portal/src/features/<feature>/**`
  - hooks (React Query)
  - services (API client calls)
  - components/views (UI composition)
- **No provider imports** from domain in Portal.

### Naming & safety

- No `any` in public APIs
- Avoid unsafe assertions
- No `console.log` in production code (use logger)
- Avoid `V2` suffix in service names

### References

- `docs/development/domain/import-hygiene.md`
- `docs/development/bff/integration-patterns.md`
- `docs/development/portal/architecture.md`

