# Code Review Guidelines
## Always check
### RBAC & Security
- Every customer-facing API endpoint MUST have `@UseGuards(HybridAuthGuard, PermissionGuard)` and `@RequirePermission('resource', 'action')`
- `@Public()` is only acceptable for webhooks and unauthenticated endpoints (e.g., trust portal public pages)
- No manual role string parsing (`role.includes('admin')`) — always use permission check utilities
- Frontend mutation buttons must be gated with `hasPermission(permissions, 'resource', 'action')`
- Raw `fetch()` calls to the API must include `credentials: 'include'`
- Database queries must be scoped by `organizationId` for multi-tenancy
- Error messages must not leak internal details (stack traces, DB structure, internal IDs)
### Server Actions & API Architecture
- No new server actions — client components should call the NestJS API directly via `apiClient`/`api` or SWR hooks
- No `useAction` from `next-safe-action` in new code
- No direct `@db` imports in the Next.js app for mutations — all mutations go through the NestJS API
- Server actions are acceptable ONLY for server-side-only operations like encryption/decryption that need access to server env vars
- Multi-step orchestration should use Next.js API routes (`apps/app/src/app/api/...`), not server actions
### Design System
- New UI must use `@trycompai/design-system` components, not `@trycompai/ui` (legacy, being phased out)
- Icons must come from `@trycompai/design-system/icons` (Carbon icons), not `lucide-react`
- DS components `Text`, `Stack`, `HStack`, `Badge`, `Button` do not accept `className` — wrap in a `
` for custom styling
- Use DS `Button` props like `loading`, `iconLeft`, `iconRight` instead of manually rendering spinners/icons inside buttons
### TypeScript
- No `as any` casts — use proper types, generics, or `unknown` with type guards
- No `@ts-ignore` or `@ts-expect-error` — fix the underlying type issue
- Files must not exceed 300 lines — split into focused modules
### Data Fetching
- Client components should use `useSWR` with `apiClient` or custom hooks
- Server components should fetch with `serverApi` and pass as `fallbackData`
- `mutate()` optimistic update functions must guard against `undefined` input
- Use `Array.isArray()` checks when consuming SWR data that could be stale
### Database
- New IDs must use prefixed CUIDs: `@default(dbgenerated("generate_prefixed_cuid('prefix'::text)"))`
- Operations modifying multiple records must use transactions
- Migrations must be backward-compatible
### API Controller Format
- Controllers must use `@Controller({ path: 'name', version: '1' })`, NOT `@Controller('v1/name')` (causes double prefix bug)
- API list endpoints return `{ data: [...], count }` — single resource endpoints return the entity flat
### Forms
- Forms must use React Hook Form + Zod validation
- No `useState` for form field values — use the form's state management
## Skip
- Pre-existing `@trycompai/ui` usage in files not touched by the PR
- Pre-existing `lucide-react` usage in files not touched by the PR
- Pre-existing server actions in files not touched by the PR
- Test files using simplified mock types
- Generated files under `packages/db/prisma/generated/`
- OpenAPI spec file `packages/docs/openapi.json`