<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harshit Rathod</title>
    <description>The latest articles on DEV Community by Harshit Rathod (@harshit_rathod).</description>
    <link>https://dev.to/harshit_rathod</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972207%2F3affed39-1b37-462a-8eb0-c163842a5353.jpg</url>
      <title>DEV Community: Harshit Rathod</title>
      <link>https://dev.to/harshit_rathod</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harshit_rathod"/>
    <language>en</language>
    <item>
      <title>Claude Code for NestJS Monorepos: A Practical Setup Guide</title>
      <dc:creator>Harshit Rathod</dc:creator>
      <pubDate>Sun, 07 Jun 2026 08:53:54 +0000</pubDate>
      <link>https://dev.to/harshit_rathod/claude-code-for-nestjs-monorepos-a-practical-setup-guide-46l8</link>
      <guid>https://dev.to/harshit_rathod/claude-code-for-nestjs-monorepos-a-practical-setup-guide-46l8</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical, step-by-step guide to configuring Claude Code with CLAUDE.md, rules, and skills so AI-generated code matches your team's conventions in a large NestJS monorepo.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hook:&lt;/strong&gt; Ask Claude to "add a consumer-visible status to a booking" in an unconfigured monorepo, and it will happily edit the &lt;em&gt;wrong microservice&lt;/em&gt;, hardcode an error string, and check &lt;code&gt;user.role === 'admin'&lt;/code&gt;. None of that is Claude being wrong — it's Claude guessing. This guide removes the guessing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code reads &lt;code&gt;.claude/&lt;/code&gt; from your git root&lt;/strong&gt;, so one configuration governs every service in the monorepo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three mechanisms do the heavy lifting:&lt;/strong&gt; &lt;code&gt;CLAUDE.md&lt;/code&gt; (always-loaded project briefing), &lt;strong&gt;rules&lt;/strong&gt; (hard prohibitions), and &lt;strong&gt;skills&lt;/strong&gt; (multi-step workflows with templates).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The single biggest win is service routing&lt;/strong&gt; — a decision table in &lt;code&gt;CLAUDE.md&lt;/code&gt; stops Claude from putting consumer logic in the operator service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write rules as prohibitions, not preferences&lt;/strong&gt; — "NEVER query the DB in a loop" is enforced; "prefer bulk queries" is ignored under pressure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup is a few hours, one-time&lt;/strong&gt;, and pays back on every feature: faster scaffolding, fewer convention violations in review, and faster onboarding.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Answer
&lt;/h2&gt;

&lt;p&gt;To set up Claude Code for a NestJS monorepo: &lt;br&gt;
(1) install it with &lt;code&gt;npm install -g @anthropic-ai/claude-code&lt;/code&gt; and authenticate once via &lt;code&gt;claude&lt;/code&gt;; (2) create a root &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt; that documents which service owns what, your request pipeline, and your standard response shape; (3) add a &lt;code&gt;.claude/rules/&lt;/code&gt; folder with hard prohibitions (no N+1 queries, no role-name checks, no relative imports); (4) build a &lt;code&gt;.claude/skills/&lt;/code&gt; folder with multi-step workflows and code templates for repeated tasks like creating an endpoint; and (5) add &lt;code&gt;.claude/settings.json&lt;/code&gt; to allow safe commands and deny destructive ones. Commit &lt;code&gt;.claude/&lt;/code&gt; to git so the whole team shares it. The result: Claude generates code that follows your conventions on the first try, instead of guessing.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem: Why Claude Struggles With Large NestJS Projects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A large NestJS monorepo is one of the hardest environments for any AI coding assistant, because correctness depends on conventions that are invisible in any single file.&lt;/strong&gt; A codebase with dozens of modules, hundreds of DTOs, and custom guards, interceptors, filters, and adapters is genuinely ambiguous. Without context, Claude fills that ambiguity with reasonable defaults — and those defaults won't match your team's conventions.&lt;/p&gt;

&lt;p&gt;Concretely, an unconfigured Claude will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call the database directly from a service instead of going through a repository&lt;/li&gt;
&lt;li&gt;Hardcode error strings instead of using your &lt;code&gt;ErrorMessages&lt;/code&gt; constants&lt;/li&gt;
&lt;li&gt;Put a new file in the wrong service (booking logic in &lt;code&gt;operator-service&lt;/code&gt; when it belongs in &lt;code&gt;api-service&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;user.role === 'admin'&lt;/code&gt; instead of using &lt;code&gt;PermissionCodes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;console.log&lt;/code&gt; instead of your structured logger&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;../../common/utils&lt;/code&gt; instead of the &lt;code&gt;src/&lt;/code&gt; path alias&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Why This Problem Exists
&lt;/h2&gt;

&lt;p&gt;These aren't bugs in Claude — they're the predictable result of asking a model to infer team-specific decisions it was never told about. An AI assistant only sees the files it reads in a session; it cannot see &lt;em&gt;why&lt;/em&gt; your team removed &lt;code&gt;RolesGuard&lt;/code&gt;, that &lt;code&gt;synchronize&lt;/code&gt; must stay &lt;code&gt;false&lt;/code&gt;, or that two services communicate only over HTTP adapters. Tribal knowledge that lives in your engineers' heads is exactly the knowledge Claude lacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix is to externalize that tribal knowledge into version-controlled context&lt;/strong&gt; through three mechanisms, each suited to a different kind of knowledge:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;What it encodes&lt;/th&gt;
&lt;th&gt;When Claude uses it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Architecture, ownership, conventions&lt;/td&gt;
&lt;td&gt;Loaded automatically every session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard prohibitions and invariants&lt;/td&gt;
&lt;td&gt;Enforced on every code generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skills&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-step workflows + templates&lt;/td&gt;
&lt;td&gt;Invoked on demand for repeated tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Repository Structure
&lt;/h2&gt;

&lt;p&gt;Before configuring anything, anchor on the layout. A well-structured NestJS monorepo looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-backend/
├── .claude/                  # Everything Claude needs to operate well
│   ├── CLAUDE.md             # Root-level instructions (always loaded)
│   ├── rules/                # Enforced coding constraints
│   ├── skills/               # Custom slash commands with deep context
│   └── settings.json         # Command permissions
├── services/
│   ├── api-service/          # NestJS consumer API (port 5001)
│   ├── operator-service/     # NestJS operator/vendor API (port 5002)
│   ├── chat-service/         # Express + Socket.IO (JavaScript, port 5005)
│   └── job-service/          # Scheduled jobs, no HTTP server
├── db/migration/             # Flyway migrations per schema
└── package.json              # Root: only husky + lint-staged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each service is an independent NestJS app with its own &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;tsconfig.json&lt;/code&gt;, and build output. Inside each service, every feature module follows the same strict three-layer structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/modules/booking/
├── booking.module.ts
├── controllers/    # HTTP routing only, no logic
├── services/       # Business logic and orchestration
├── repositories/   # TypeORM queries only
└── dtos/           # Request/response shapes, validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; This separation is exactly what Claude needs to respect. If it doesn't know the pattern, it mixes layers — services querying the DB directly, controllers calling repositories.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Suggested visual: a diagram of the git-root &lt;code&gt;.claude/&lt;/code&gt; directory applying across all four services.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step: Configuring Claude Code for NestJS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Install Claude Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
claude   &lt;span class="c"&gt;# opens a browser for one-time OAuth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After authenticating, &lt;code&gt;claude&lt;/code&gt; works from any directory. Each developer installs and authenticates independently — there's no shared API key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Monorepo tip:&lt;/strong&gt; Claude reads &lt;code&gt;.claude/&lt;/code&gt; from the &lt;strong&gt;git root&lt;/strong&gt;, so its instructions apply no matter where you invoke Claude. When working on one service, &lt;code&gt;cd&lt;/code&gt; into it (e.g. &lt;code&gt;services/api-service/&lt;/code&gt;) so file searches and commands scope correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2 — Create CLAUDE.md
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; is the single most important file you will write — it's the briefing Claude reads at the start of every session.&lt;/strong&gt; Think of it as onboarding documentation for a senior engineer on day one. Place it at two levels:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Root &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt;&lt;/strong&gt; — service ownership, shared conventions, the request pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-service &lt;code&gt;services/{service}/CLAUDE.md&lt;/code&gt;&lt;/strong&gt; — module patterns, auth, and DI specific to that service&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  The Root CLAUDE.md
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Claude can't tell which service should own a new file, so it guesses — and lands consumer logic in the operator service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; A routing decision table plus explicit "never do this" rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; Files land in the correct service on the first pass.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# CLAUDE.md&lt;/span&gt;

&lt;span class="gu"&gt;## Monorepo Structure&lt;/span&gt;

Four services under &lt;span class="sb"&gt;`services/`&lt;/span&gt;, each independently runnable.
Run all commands from inside the service directory.

| Service            | Port | Stack                    | Purpose              |
| ------------------ | ---- | ------------------------ | -------------------- |
| &lt;span class="sb"&gt;`api-service`&lt;/span&gt;      | 5001 | NestJS + TypeScript      | Consumer-facing API  |
| &lt;span class="sb"&gt;`operator-service`&lt;/span&gt; | 5002 | NestJS + TypeScript      | Operator/vendor mgmt |
| &lt;span class="sb"&gt;`chat-service`&lt;/span&gt;     | 5005 | Express + Socket.IO + JS | Real-time messaging  |
| &lt;span class="sb"&gt;`job-service`&lt;/span&gt;      | —    | Node.js + TypeScript     | Scheduled jobs       |

&lt;span class="gu"&gt;## Which Service Owns What&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**operator-service**&lt;/span&gt; — if the data describes _what an experience is_:
  package definitions, pricing, taxes, availability, operator accounts.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**api-service**&lt;/span&gt; — if the data describes _a consumer's interaction_:
  bookings, users, auth, trip planning, payments, notifications.

| Task involves...                   | Service                            |
| ---------------------------------- | ---------------------------------- |
| Package categories, pricing, slots | operator-service                   |
| Booking status, user profiles      | api-service                        |
| Stripe payments (consumer side)    | api-service                        |
| Cross-service booking flow         | Start in api-service → IMS adapter |

&lt;span class="gu"&gt;## Global Request Pipeline (in order)&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="sb"&gt;`TraceContextMiddleware`&lt;/span&gt; — sets &lt;span class="sb"&gt;`correlationId`&lt;/span&gt; in &lt;span class="sb"&gt;`AsyncLocalStorage`&lt;/span&gt;
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="sb"&gt;`ValidationPipe`&lt;/span&gt; — whitelist mode, flattens DTO errors
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="sb"&gt;`LoggerInterceptor`&lt;/span&gt; — logs request/response
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="sb"&gt;`TransformInterceptor`&lt;/span&gt; — wraps return value in the standard shape
&lt;span class="p"&gt;5.&lt;/span&gt; Exception filters (&lt;span class="sb"&gt;`HttpExceptionFilter`&lt;/span&gt;, &lt;span class="sb"&gt;`TypeOrmExceptionFilter`&lt;/span&gt;, …)

&lt;span class="gu"&gt;## Standard Response Shape&lt;/span&gt;

Controllers return &lt;span class="sb"&gt;`{ data, meta }`&lt;/span&gt;; &lt;span class="sb"&gt;`TransformInterceptor`&lt;/span&gt; wraps it:
return { data: { items }, meta: { path: request.path } };
// → { success: true, data: { items }, meta: { path }, error: null }

&lt;span class="gu"&gt;## Cross-Service Communication&lt;/span&gt;

api-service NEVER touches operator-service's database. All reads/writes go
through HTTP adapters in &lt;span class="sb"&gt;`src/common/adapters/`&lt;/span&gt; (they handle OAuth refresh and
trace propagation). Need operator data? Call the adapter, never the DB.

&lt;span class="gu"&gt;## What Claude Must Never Do&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Use &lt;span class="sb"&gt;`console.log`&lt;/span&gt; → use &lt;span class="sb"&gt;`logMessage()`&lt;/span&gt; from &lt;span class="sb"&gt;`src/common/utils/logger`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Check &lt;span class="sb"&gt;`user.role`&lt;/span&gt; → use &lt;span class="sb"&gt;`PermissionCodes`&lt;/span&gt; + &lt;span class="sb"&gt;`@Permissions()`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Query the DB inside a loop → use bulk queries (&lt;span class="sb"&gt;`IN`&lt;/span&gt;, &lt;span class="sb"&gt;`JOIN`&lt;/span&gt;)
&lt;span class="p"&gt;-&lt;/span&gt; Use relative &lt;span class="sb"&gt;`../../`&lt;/span&gt; imports → use the &lt;span class="sb"&gt;`src/`&lt;/span&gt; alias
&lt;span class="p"&gt;-&lt;/span&gt; Set TypeORM &lt;span class="sb"&gt;`synchronize: true`&lt;/span&gt; → Flyway manages all schema changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What makes a good CLAUDE.md:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision rules over directory listings.&lt;/strong&gt; "If the data describes what an experience &lt;em&gt;is&lt;/em&gt;, it lives in operator-service" lets Claude resolve ambiguity without asking you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include the response shape.&lt;/strong&gt; Otherwise Claude manually wraps responses in every controller, creating inconsistencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List what NOT to do.&lt;/strong&gt; "Never use &lt;code&gt;console.log&lt;/code&gt;" is more actionable than "use our logger."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document what was removed.&lt;/strong&gt; When you delete a &lt;code&gt;RolesGuard&lt;/code&gt; or a &lt;code&gt;synchronize&lt;/code&gt; flag, say why — or Claude will reintroduce it because it looks natural.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Service-Level CLAUDE.md
&lt;/h4&gt;

&lt;p&gt;Each service gets its own file for details too specific for the root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# api-service/CLAUDE.md&lt;/span&gt;

&lt;span class="gu"&gt;## Module Architecture — never mix layers&lt;/span&gt;

controllers/ HTTP routing only — call service, return data
services/ Business logic — orchestrate repos, no direct DB calls
repositories/ TypeORM queries only — accept EntityManager for transactions

&lt;span class="gu"&gt;## Authentication&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="sb"&gt;`JwtAuthGuard`&lt;/span&gt; validates Bearer tokens, attaches &lt;span class="sb"&gt;`UserRequest`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`PermissionsGuard`&lt;/span&gt; reads &lt;span class="sb"&gt;`@Permissions([PermissionCodes.X])`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Never use RolesGuard or check role names — removed intentionally

&lt;span class="gu"&gt;## Dependency Injection&lt;/span&gt;

Register services by interface token, and inject by token, not class:
{ provide: SERVICE_INTERFACE.BOOKING_SERVICE, useClass: BookingService }

&lt;span class="gu"&gt;## Background Jobs&lt;/span&gt;

BullMQ + Redis. Processors live in &lt;span class="sb"&gt;`src/modules/{module}/processors/`&lt;/span&gt;.
Enqueue via the module's service — never from a controller.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 — Add Rules
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rules are hard prohibitions — they don't describe architecture, they prevent specific patterns, like an ESLint config for AI-generated code.&lt;/strong&gt; They live in &lt;code&gt;.claude/rules/&lt;/code&gt; as Markdown files.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use &lt;code&gt;CLAUDE.md&lt;/code&gt; for&lt;/th&gt;
&lt;th&gt;Use &lt;code&gt;rules/&lt;/code&gt; for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Architecture, module structure&lt;/td&gt;
&lt;td&gt;Hard prohibitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service ownership decisions&lt;/td&gt;
&lt;td&gt;Patterns Claude must never emit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conventions, command reference&lt;/td&gt;
&lt;td&gt;Security / performance invariants&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Rule: Prevent N+1 Queries
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; N+1 queries are easy to introduce and slip through review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; a prohibition rule with a correct bulk-query pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; Claude writes the bulk query at generation time — the bug is never created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;.claude/rules/database-queries.md&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong — N queries&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;bookings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Correct — one query&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;In&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;span class="nx"&gt;bookings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Rule: Permission Checks
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;.claude/rules/permissions.md&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Correct&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Permissions&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;PermissionCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MANAGE_BOOKINGS&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UseGuards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JwtAuthGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PermissionsGuard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; role names get merged, split, and renamed; checks against them break&lt;br&gt;
silently. &lt;code&gt;PermissionCodes&lt;/code&gt; are stable constants that survive role&lt;br&gt;
restructuring. Import from &lt;code&gt;src/common/constants/permissions.constant.ts&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Rule: Import Style
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;.claude/rules/imports.md&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../services/user.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Correct&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/modules/user/services/user.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;src/&lt;/code&gt; alias is configured in &lt;code&gt;tsconfig.json&lt;/code&gt; (&lt;code&gt;baseUrl: "./"&lt;/code&gt;) and Jest's&lt;br&gt;
&lt;code&gt;moduleNameMapper&lt;/code&gt;. Use it everywhere.&lt;/p&gt;
&lt;h4&gt;
  
  
  Other Rules Worth Defining
&lt;/h4&gt;

&lt;p&gt;The same prohibition pattern applies to many recurring NestJS pitfalls. A few more rules worth their own file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error handling&lt;/strong&gt; — always throw from &lt;code&gt;ErrorMessages&lt;/code&gt;/&lt;code&gt;ResponseCodeKeys&lt;/code&gt; constants and use NestJS exceptions; never hardcode strings or return raw error objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt; — use the structured &lt;code&gt;logMessage()&lt;/code&gt; helper at the right level; never &lt;code&gt;console.log&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions&lt;/strong&gt; — multi-write operations must run in a single &lt;code&gt;EntityManager&lt;/code&gt; transaction; never fire independent writes that can half-commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DTO validation&lt;/strong&gt; — every request DTO needs &lt;code&gt;class-validator&lt;/code&gt; decorators; the &lt;code&gt;ValidationPipe&lt;/code&gt; whitelist drops anything undecorated, so missing decorators silently lose data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity ↔ migration parity&lt;/strong&gt; — any entity change needs a matching Flyway migration; &lt;code&gt;synchronize&lt;/code&gt; stays &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swagger coverage&lt;/strong&gt; — every endpoint carries &lt;code&gt;@ApiSpec&lt;/code&gt; + a typed response DTO so the generated docs stay accurate.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 4 — Build Skills
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Skills are project-specific slash commands that bundle a workflow, code templates, and references — they turn a repeated multi-file task into one command.&lt;/strong&gt; Write one for any repeated, multi-step task: building an endpoint, writing a migration, scaffolding a module, reviewing a PR.&lt;/p&gt;
&lt;h4&gt;
  
  
  Skill Structure
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/skills/api-development/
├── SKILL.md                    # Workflow, trigger, steps
├── assets/
│   ├── controller-template.md
│   ├── service-template.md
│   ├── repository-template.md
│   └── dto-template.md
└── references/
    ├── nestjs-conventions.md
    └── swagger-documentation.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Writing SKILL.md
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# API Development Skill&lt;/span&gt;

&lt;span class="gu"&gt;## Trigger&lt;/span&gt;

Invoke with &lt;span class="sb"&gt;`/api-development`&lt;/span&gt; when building or modifying a NestJS endpoint.

&lt;span class="gu"&gt;## Workflow&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**Determine service &amp;amp; module**&lt;/span&gt; — check CLAUDE.md routing; ask if ambiguous.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Read what exists**&lt;/span&gt; — entities, repositories, DTOs already in the module.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the DTO first**&lt;/span&gt; — it defines the contract. class-validator
   decorators; extend &lt;span class="sb"&gt;`PaginationRequestDTO`&lt;/span&gt; for lists.
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the repository**&lt;/span&gt; — inject &lt;span class="sb"&gt;`DataSource`&lt;/span&gt;; accept an optional
   &lt;span class="sb"&gt;`EntityManager`&lt;/span&gt; for transactions; queries only, no logic.
&lt;span class="p"&gt;5.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the service**&lt;/span&gt; — inject the repository interface token; use
   &lt;span class="sb"&gt;`ErrorMessages`&lt;/span&gt; constants; throw &lt;span class="sb"&gt;`NotFoundException`&lt;/span&gt; etc.
&lt;span class="p"&gt;6.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the controller**&lt;/span&gt; — &lt;span class="sb"&gt;`@ApiSpec`&lt;/span&gt; + &lt;span class="sb"&gt;`@ApiOkResponse`&lt;/span&gt;; return
   &lt;span class="sb"&gt;`{ data, meta }`&lt;/span&gt;; no business logic.
&lt;span class="p"&gt;7.&lt;/span&gt; &lt;span class="gs"&gt;**Wire the module**&lt;/span&gt; — add to &lt;span class="sb"&gt;`providers`&lt;/span&gt;, export by interface token.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Asset Template (example)
&lt;/h4&gt;

&lt;p&gt;Templates should be real, compilable code — not pseudocode. &lt;code&gt;assets/controller-template.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ApiTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bookings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bookings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookingController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SERVICE_INTERFACE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOOKING_SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;bookingService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IBookingService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UseGuards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JwtAuthGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PermissionsGuard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Permissions&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;PermissionCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREATE_BOOKING&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ApiSpec&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Create a new booking&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ApiCreatedResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateBookingSuccessDto&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createBooking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateBookingDto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Req&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BookingEntity&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;booking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bookingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBooking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;booking&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this skill, a complete endpoint (controller + service + repository + DTOs, wired into the module) takes &lt;strong&gt;under 3 minutes instead of ~20&lt;/strong&gt; — and matches your conventions on the first try.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other Skills Worth Building
&lt;/h4&gt;

&lt;p&gt;Any repeated, multi-step workflow with team-specific conventions is a skill candidate. Beyond endpoint scaffolding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Migration generator&lt;/strong&gt; — scaffold a Flyway migration in the right schema folder with your versioning and naming convention, plus the matching entity change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module scaffolder&lt;/strong&gt; — generate a full module skeleton (module file, three layers, DI tokens) wired and ready.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR review&lt;/strong&gt; — review a diff against your conventions: N+1 checks, permission usage, layer boundaries, missing tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test generator&lt;/strong&gt; — produce &lt;code&gt;*.spec.ts&lt;/code&gt; files following your mocking and fixture patterns for a given service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-service adapter&lt;/strong&gt; — generate a new IMS adapter method plus its response interface and transform helper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use-case / BDD docs&lt;/strong&gt; — turn a requirement into user stories with Given/When/Then acceptance criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5 — Configure Settings &amp;amp; Permissions
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;.claude/settings.json&lt;/code&gt; controls which Bash commands run without a permission prompt. Allow read-only and safe test/lint operations freely; deny anything destructive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run lint:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run test:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run build)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npx jest *)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash(rm -rf *)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git push *)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git reset --hard *)"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Applies to&lt;/th&gt;
&lt;th&gt;Committed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.claude/settings.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Everyone on the team&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.claude/settings.local.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;You only (overrides)&lt;/td&gt;
&lt;td&gt;No (gitignored)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Best Practice callout:&lt;/strong&gt; Treat &lt;code&gt;.claude/&lt;/code&gt; as production code. It ships your conventions to every engineer and every AI session — review it, version it, and prune it like any other source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep CLAUDE.md under ~300 lines.&lt;/strong&gt; Context has a cost; a bloated file crowds out the code Claude needs to read. If it's derivable from the code, cut it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write rules as prohibitions, not guidance.&lt;/strong&gt; "NEVER call the DB in a loop" is enforced; "prefer bulk queries" is ignored under pressure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put templates in skills, not CLAUDE.md&lt;/strong&gt; — they should load only when the skill is invoked, not on every session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version &lt;code&gt;.claude/&lt;/code&gt; in git.&lt;/strong&gt; It's part of your codebase: same review, same history. New rules get PRs; stale rules get deleted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use decision tables liberally.&lt;/strong&gt; Anywhere two reasonable choices exist — DTO placement, entity location, service boundaries — a table beats prose.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recommended &lt;code&gt;.claude/&lt;/code&gt; layout
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/
├── CLAUDE.md                  # Root guide (&amp;lt;300 lines)
├── settings.json              # Team permissions (committed)
├── rules/
│   ├── database-queries.md    # No N+1
│   ├── permissions.md         # PermissionCodes, no role checks
│   └── imports.md             # src/ alias only
└── skills/
    └── api-development/
        ├── SKILL.md
        ├── assets/            # controller/service/repository/dto templates
        └── references/        # conventions, swagger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Each of these silently degrades output quality — Claude will &lt;em&gt;look&lt;/em&gt; like it's working while quietly violating your conventions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Writing CLAUDE.md as a tutorial.&lt;/strong&gt; Don't explain what NestJS is — Claude knows. Document only what's unique to your project: module names, error constants, response shape, permission system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omitting negative rules.&lt;/strong&gt; Telling Claude what &lt;em&gt;not&lt;/em&gt; to do prevents whole classes of mistakes. The expensive errors are the ones that look correct but violate your patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cramming everything into the root CLAUDE.md.&lt;/strong&gt; It loads in every session. Split service-specific depth into per-service files so it doesn't pollute context when you're elsewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No routing decision table.&lt;/strong&gt; Wrong-service placement comes from ambiguity, not ignorance. A table makes the decision deterministic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting the cross-service adapter pattern.&lt;/strong&gt; In an HTTP-linked monorepo, Claude will try to import across services or query the other DB. Spell out that all cross-service calls go through adapters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not mentioning &lt;code&gt;synchronize: false&lt;/code&gt;.&lt;/strong&gt; Claude assumes TypeORM manages the schema. If you use Flyway, entity changes without a matching migration fail silently — say so explicitly.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Real-World Example: Adding a Consumer-Visible Booking Status
&lt;/h2&gt;

&lt;p&gt;A walkthrough of how a configured setup changes one real task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The request:&lt;/strong&gt; &lt;em&gt;"Add a consumer-visible status to a booking package."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without configuration&lt;/strong&gt;, Claude reasons: "packages live in &lt;code&gt;operator-service&lt;/code&gt;," and edits the package entity there — the wrong service. It hardcodes the status string, and adds an &lt;code&gt;if (user.roles.includes('admin'))&lt;/code&gt; guard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With configuration&lt;/strong&gt;, here's the chain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Routing table&lt;/strong&gt; in &lt;code&gt;CLAUDE.md&lt;/code&gt; tells Claude that &lt;em&gt;consumer-visible&lt;/em&gt; status describes a consumer interaction → it belongs in &lt;code&gt;api-service&lt;/code&gt;, not &lt;code&gt;operator-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-service rule&lt;/strong&gt; reminds it the operator's package definition is read via an IMS adapter, so it adds the field to the adapter's transform — not by reaching into the other DB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/api-development&lt;/code&gt; skill&lt;/strong&gt; scaffolds the DTO, repository method, service logic, and controller in the right order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission rule&lt;/strong&gt; makes it emit &lt;code&gt;@Permissions([PermissionCodes.VIEW_BOOKING_STATUS])&lt;/code&gt; instead of a role check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error rule&lt;/strong&gt; makes it throw &lt;code&gt;NotFoundException&lt;/code&gt; with an &lt;code&gt;ErrorMessages&lt;/code&gt; constant.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One ambiguous sentence, resolved into correct, convention-matching code across four files — without a single clarifying question.&lt;/p&gt;




&lt;h2&gt;
  
  
  Results &amp;amp; Metrics
&lt;/h2&gt;

&lt;p&gt;A few hours of one-time setup changes the day-to-day in measurable ways:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Review every generated file for hardcoded strings, wrong imports, role checks&lt;/td&gt;
&lt;td&gt;Rules make those impossible — review focuses on logic, not conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New endpoint ≈ 20 min wiring four layers by hand&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/api-development&lt;/code&gt; scaffolds + wires it in under 3 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files landed in the wrong service, caught late in review&lt;/td&gt;
&lt;td&gt;Routing table places them correctly on the first pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N+1 queries and &lt;code&gt;console.log&lt;/code&gt; slipped into PRs&lt;/td&gt;
&lt;td&gt;Caught at generation time, never written&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New hires guessed at module boundaries and patterns&lt;/td&gt;
&lt;td&gt;CLAUDE.md teaches the conventions implicitly on day one&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Compounding wins that don't show up in a single PR:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency.&lt;/strong&gt; Code generated months apart looks the same, because it comes from the same templates and rules — not from whatever Claude inferred that day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less review fatigue.&lt;/strong&gt; Reviewers stop flagging the same convention violations and spend attention on actual design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster onboarding.&lt;/strong&gt; Routing tables and rules are documentation that also executes — a new engineer's first AI-assisted feature already follows house style.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower context cost.&lt;/strong&gt; A tight CLAUDE.md plus on-demand skills means Claude spends its context budget reading &lt;em&gt;your&lt;/em&gt; code, not re-deriving conventions every session.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extractable insight:&lt;/strong&gt; The investment pays for itself within the first few features and keeps paying on every one after — because the cost is one-time and the benefit recurs on every task.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is CLAUDE.md?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; is a Markdown file Claude Code reads automatically at the start of every session. It briefs the AI on your project's architecture, conventions, and prohibitions — the equivalent of onboarding docs for a new engineer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where should CLAUDE.md go in a monorepo?&lt;/strong&gt;&lt;br&gt;
Put a root &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt; at the git root for cross-cutting concerns (service ownership, shared conventions), and a &lt;code&gt;CLAUDE.md&lt;/code&gt; inside each service for service-specific patterns. Claude reads the root first, then the service-level file when you work in that directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between CLAUDE.md and rules?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; describes architecture and conventions; rules (in &lt;code&gt;.claude/rules/&lt;/code&gt;) are hard prohibitions Claude must never violate. Use &lt;code&gt;CLAUDE.md&lt;/code&gt; for "here's how things work" and rules for "never do this," such as banning N+1 queries or role-name checks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do Claude Code skills work?&lt;/strong&gt;&lt;br&gt;
A skill is a project-specific slash command (e.g. &lt;code&gt;/api-development&lt;/code&gt;) backed by a &lt;code&gt;SKILL.md&lt;/code&gt; workflow plus code templates and references. Invoking it makes Claude follow a deterministic, multi-step process — like scaffolding a full NestJS endpoint across four files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long should CLAUDE.md be?&lt;/strong&gt;&lt;br&gt;
Aim for under ~300 lines. Context is finite, and a bloated file crowds out the actual code Claude needs to read. Document only what isn't derivable from the codebase itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does Claude Code work with a NestJS monorepo of multiple services?&lt;/strong&gt;&lt;br&gt;
Yes. Claude reads &lt;code&gt;.claude/&lt;/code&gt; from the git root, so one configuration governs every service. A routing decision table in &lt;code&gt;CLAUDE.md&lt;/code&gt; tells Claude which service owns which kind of data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I stop Claude from writing N+1 queries or role-based permission checks?&lt;/strong&gt;&lt;br&gt;
Add prohibition rules in &lt;code&gt;.claude/rules/&lt;/code&gt;. A &lt;code&gt;database-queries.md&lt;/code&gt; rule bans DB calls inside loops; a &lt;code&gt;permissions.md&lt;/code&gt; rule bans &lt;code&gt;user.role&lt;/code&gt; checks in favor of &lt;code&gt;PermissionCodes&lt;/code&gt; and &lt;code&gt;@Permissions()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I commit the .claude directory to git?&lt;/strong&gt;&lt;br&gt;
Yes — commit &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt;, &lt;code&gt;rules/&lt;/code&gt;, &lt;code&gt;skills/&lt;/code&gt;, and &lt;code&gt;settings.json&lt;/code&gt; so the whole team shares the same configuration. Keep personal overrides in &lt;code&gt;.claude/settings.local.json&lt;/code&gt;, which is gitignored.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways (Recap)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Claude struggles in large NestJS monorepos because &lt;strong&gt;correctness depends on conventions invisible in any single file&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Externalize that knowledge with &lt;strong&gt;CLAUDE.md (briefing), rules (prohibitions), and skills (workflows)&lt;/strong&gt; — all committed to git.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;service-routing decision table&lt;/strong&gt; is the highest-leverage thing you can write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules phrased as prohibitions&lt;/strong&gt; are enforced; preferences are not.&lt;/li&gt;
&lt;li&gt;Setup is &lt;strong&gt;a few hours, one-time&lt;/strong&gt;, and compounds across every feature and every new hire.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Setting up Claude Code for a NestJS monorepo isn't about making Claude smarter — it's about eliminating guesswork. A codebase with dozens of modules, hundreds of DTOs, and custom guards and adapters is genuinely ambiguous without context, and Claude's reasonable defaults won't match your conventions.&lt;/p&gt;

&lt;p&gt;The investment is small and one-time: a focused &lt;code&gt;CLAUDE.md&lt;/code&gt; for routing and prohibitions, a few rules files for hard constraints, and one or two skills for your most repeated tasks. After that, Claude generates code that looks like your team wrote it — not like someone who just read the NestJS docs.&lt;/p&gt;




&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.claude.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code documentation&lt;/a&gt; — official setup, configuration, and best-practices reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.nestjs.com" rel="noopener noreferrer"&gt;NestJS documentation&lt;/a&gt; — providers, guards, interceptors, and module architecture&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://typeorm.io" rel="noopener noreferrer"&gt;TypeORM&lt;/a&gt; · &lt;a href="https://github.com/typestack/class-validator" rel="noopener noreferrer"&gt;class-validator&lt;/a&gt; · &lt;a href="https://documentation.red-gate.com/flyway" rel="noopener noreferrer"&gt;Flyway&lt;/a&gt; — the data, validation, and migration tooling referenced above&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Patterns here are drawn from a production NestJS monorepo running four services: a consumer API, an operator management system, a real-time chat service, and a scheduled job runner. The approach scales to any NestJS project with conventions worth preserving.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>claudecode</category>
      <category>ai</category>
      <category>monorepo</category>
    </item>
  </channel>
</rss>
