nestjs-repository-pattern — nestjs-repository-pattern install nestjs-repository-pattern, maintenance-management-system, community, nestjs-repository-pattern install, ide skills, nestjs-repository-pattern prisma orm, clean architecture nestjs, repository pattern nestjs, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Perfect for Full-Stack Agents needing clean architecture guidelines for NestJS applications with Prisma ORM nestjs-repository-pattern is a set of guidelines for implementing the repository pattern in NestJS applications, focusing on clean architecture and database access with Prisma ORM.

Features

Implements data access layers with Prisma ORM
Provides guidelines for writing queries for User, Asset, Site, and other entities
Supports transaction support for database operations
Organizes code for testability and maintainability
Refactors services that contain direct Prisma/DB calls
Creates new NestJS modules with database access

# Core Topics

Just-DX Just-DX
[0]
[0]
Updated: 3/8/2026

Agent Capability Analysis

The nestjs-repository-pattern skill by Just-DX is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for nestjs-repository-pattern install, nestjs-repository-pattern prisma orm, clean architecture nestjs.

Ideal Agent Persona

Perfect for Full-Stack Agents needing clean architecture guidelines for NestJS applications with Prisma ORM

Core Value

Empowers agents to implement the repository pattern, providing a maintainable data access layer with Prisma ORM, and enabling clean architecture for NestJS modules, services, and database transactions

Capabilities Granted for nestjs-repository-pattern

Implementing data access layers for User, Asset, and Site entities
Refactoring services to remove direct Prisma/DB calls
Setting up transaction support for NestJS applications
Organizing code for testability and maintainability

! Prerequisites & Limits

  • Requires NestJS and Prisma ORM setup
  • Limited to NestJS applications
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

nestjs-repository-pattern

Install nestjs-repository-pattern, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command...

SKILL.md
Readonly

NestJS Repository Pattern Best Practices

Clean architecture guidelines for implementing repository pattern in NestJS applications with Prisma ORM.

When to Apply

Reference these guidelines when:

  • Creating new NestJS modules with database access
  • Refactoring services that contain direct Prisma/DB calls
  • Implementing data access layers
  • Writing queries for User, Asset, Site, or other entities
  • Setting up transaction support
  • Organizing code for testability and maintainability

Core Principles

1. Separation of Concerns (CRITICAL)

Rule: All Prisma/DB queries MUST live in repository classes, not in services or controllers.

typescript
1// ❌ INCORRECT: Direct Prisma call in service 2@Injectable() 3export class AssetService { 4 async findById(id: string) { 5 return await prisma.asset.findFirst({ where: { id } }) 6 } 7} 8 9// ✅ CORRECT: Repository handles data access 10@Injectable() 11export class AssetsRepository { 12 async findById(id: string, siteId: string, select?: Prisma.AssetSelect) { 13 return prisma.asset.findFirst({ where: { id, siteId }, select }) 14 } 15} 16 17@Injectable() 18export class AssetService { 19 constructor(private readonly assetsRepo: AssetsRepository) {} 20 21 async findById(id: string, siteId: string) { 22 const asset = await this.assetsRepo.findById(id, siteId, this.select) 23 if (!asset) throw new NotFoundException('Asset not found') 24 return asset 25 } 26}

Why: Enables testing, reusability, and clear architectural boundaries.

2. Repository Ownership (CRITICAL)

Rule: Each entity gets ONE repository. The repository is owned by the module that manages that entity as its "main table."

Entity Ownership Map:

EntityRepositoryModuleLocation
UserUsersRepositoryusersmodules/users/repositories/users.repository.ts
AssetAssetsRepositoryassetsmodules/assets/repositories/assets.repository.ts
SiteSitesRepositorysitemodules/site/repositories/sites.repository.ts

Cross-Module Usage:

typescript
1// ✅ CORRECT: Auth module imports users module to access UsersRepository 2@Module({ 3 imports: [UsersModule], // Import the module 4 providers: [AuthService], 5}) 6export class AuthModule {} 7 8@Injectable() 9export class AuthService { 10 constructor( 11 private readonly usersRepo: UsersRepository // Inject from imported module 12 ) {} 13}

Anti-Pattern:

typescript
1// ❌ INCORRECT: Duplicating user queries in auth.repository.ts 2// If you need user queries, use UsersRepository from users module

3. Repository Content (HIGH)

Rule: Repositories contain ONLY data access code. No business logic, no HTTP exceptions.

typescript
1// ✅ CORRECT: Repository returns null, no exceptions 2@Injectable() 3export class UsersRepository { 4 async findById(id: string): Promise<User | null> { 5 return prisma.user.findUnique({ where: { id } }) 6 // Returns null if not found - let service decide what to do 7 } 8} 9 10// ✅ CORRECT: Service adds business logic and HTTP exceptions 11@Injectable() 12export class UserService { 13 async getUser(id: string): Promise<UserDto> { 14 const user = await this.usersRepo.findById(id) 15 if (!user) { 16 throw new NotFoundException('User not found') // HTTP exception 17 } 18 if (!user.isActive) { 19 throw new ForbiddenException('User is inactive') // Business rule 20 } 21 return this.transformToDto(user) // Business logic 22 } 23}

4. Method Naming Conventions (HIGH)

Rule: Use consistent prefixes that signal behavior.

Repository Methods:

  • find* - Returns null if not found
  • create - Creates and returns record
  • update - Updates and returns record
  • softDelete / delete - Deletes record
  • count - Returns count
typescript
1@Injectable() 2export class UsersRepository { 3 // Returns null if not found 4 async findById(id: string): Promise<User | null> 5 async findByEmail(email: string): Promise<User | null> 6 7 // Returns created/updated record 8 async create(data: CreateData): Promise<User> 9 async update(id: string, data: UpdateData): Promise<User> 10 11 // Soft delete 12 async softDelete(id: string): Promise<User> 13}

Service Methods:

  • find* - May return null or throw (business decision)
  • get* - Expected to exist, throws if not found
  • create / update / remove - Operations with validation
typescript
1@Injectable() 2export class UserService { 3 // Throws NotFoundException if not found 4 async getUser(id: string): Promise<UserDto> 5 6 // Returns null or record 7 async findUserByEmail(email: string): Promise<UserDto | null> 8}

5. Transaction Support (HIGH)

Rule: All repository methods MUST accept optional transaction parameter.

typescript
1// ✅ CORRECT: Repository accepts optional transaction 2@Injectable() 3export class UsersRepository { 4 async findById( 5 id: string, 6 tx?: Prisma.TransactionClient // Optional transaction 7 ): Promise<User | null> { 8 const db = tx ?? prisma // Use transaction if provided, else prisma 9 return db.user.findUnique({ where: { id } }) 10 } 11 12 async upsertUserProfile( 13 payload: CreateUserData, 14 tx?: Prisma.TransactionClient 15 ) { 16 const db = tx ?? prisma 17 18 // If already in transaction, execute directly 19 if (tx) { 20 return tx.user.upsert({ /* ... */ }) 21 } 22 23 // Otherwise create new transaction 24 return prisma.$transaction(async (innerTx) => { 25 return innerTx.user.upsert({ /* ... */ }) 26 }) 27 } 28} 29 30// ✅ CORRECT: Service coordinates transactions 31@Injectable() 32export class UserService { 33 async complexOperation(userId: string) { 34 return prisma.$transaction(async (tx) => { 35 const user = await this.usersRepo.findById(userId, tx) 36 const sites = await this.sitesRepo.findByUser(userId, tx) 37 // All operations use same transaction 38 return { user, sites } 39 }) 40 } 41}

6. Error Handling (MEDIUM)

Rule: Repositories return null or throw Prisma errors. Services transform to HTTP exceptions.

typescript
1// ✅ CORRECT: Repository doesn't catch errors 2@Injectable() 3export class AssetsRepository { 4 async create(data: CreateAssetData) { 5 return prisma.asset.create({ data }) // Prisma errors bubble up 6 } 7} 8 9// ✅ CORRECT: Service catches and transforms errors 10@Injectable() 11export class AssetService { 12 async create(dto: CreateAssetDto) { 13 try { 14 return await this.assetsRepo.create({ 15 name: dto.name.trim(), // Business logic 16 code: dto.code.trim(), 17 /* ... */ 18 }) 19 } catch (error) { 20 if (error instanceof Prisma.PrismaClientKnownRequestError) { 21 if (error.code === 'P2002') { 22 throw new ConflictException('Asset already exists') // HTTP exception 23 } 24 } 25 throw error 26 } 27 } 28}

7. Module Organization (MEDIUM)

Rule: Follow consistent folder structure for repositories.

modules/
├── users/
│   ├── users.module.ts           # Exports UsersRepository
│   └── repositories/
│       └── users.repository.ts   # All User queries
├── assets/
│   ├── assets.module.ts          # Provides AssetsRepository
│   ├── controllers/
│   │   └── asset.controller.ts
│   ├── services/
│   │   └── asset.service.ts      # Uses AssetsRepository
│   └── repositories/
│       └── assets.repository.ts  # All Asset queries
└── site/
    ├── site.module.ts
    ├── controllers/
    ├── services/
    └── repositories/
        └── sites.repository.ts

8. Dependency Injection (MEDIUM)

Rule: Repositories are provided at module level and injected into services.

typescript
1// ✅ CORRECT: Module setup 2@Module({ 3 imports: [ListModule, AuthModule], 4 controllers: [AssetController], 5 providers: [AssetService, AssetsRepository], // Provide repository 6 exports: [AssetService, AssetsRepository], // Export for other modules 7}) 8export class AssetsModule {} 9 10// ✅ CORRECT: Service injection 11@Injectable() 12export class AssetService { 13 constructor( 14 private readonly assetsRepo: AssetsRepository // Inject repository 15 ) {} 16}

Common Patterns

Pattern 1: Simple CRUD

typescript
1// Repository 2@Injectable() 3export class AssetsRepository { 4 async findById(id: string, siteId: string, select?: Prisma.AssetSelect) { 5 return prisma.asset.findFirst({ where: { id, siteId, isDeleted: false }, select }) 6 } 7 8 async create(data: CreateAssetData, select?: Prisma.AssetSelect) { 9 return prisma.asset.create({ data, select }) 10 } 11 12 async update(id: string, data: Prisma.AssetUpdateInput, select?: Prisma.AssetSelect) { 13 return prisma.asset.update({ where: { id }, data, select }) 14 } 15 16 async softDelete(id: string) { 17 return prisma.asset.update({ where: { id }, data: { isDeleted: true } }) 18 } 19} 20 21// Service 22@Injectable() 23export class AssetService { 24 constructor(private readonly assetsRepo: AssetsRepository) {} 25 26 async findById(siteId: string, id: string): Promise<AssetDto> { 27 const asset = await this.assetsRepo.findById(id, siteId, this.select) 28 if (!asset) throw new NotFoundException('Asset not found') 29 return asset 30 } 31 32 async create(siteId: string, dto: CreateAssetDto): Promise<AssetDto> { 33 try { 34 return await this.assetsRepo.create({ 35 siteId, 36 name: dto.name.trim(), 37 code: dto.code.trim(), 38 }, this.select) 39 } catch (error) { 40 this.handlePrismaError(error) 41 } 42 } 43}

Pattern 2: Complex Queries with Relations

typescript
1// Repository 2@Injectable() 3export class UsersRepository { 4 async findUserRolesByIdAndSite( 5 userId: string, 6 siteId: string, 7 tenantId: string, 8 appScopes: AppScope[] 9 ) { 10 return prisma.userRole.findMany({ 11 where: { 12 userId, 13 siteId, 14 role: { siteId, appScope: { in: appScopes } } 15 }, 16 select: { 17 role: { 18 select: { 19 id: true, 20 code: true, 21 name: true, 22 rolePermissions: { 23 where: { permission: { tenantId, appScope: { in: appScopes } } }, 24 select: { permission: { select: { code: true } } } 25 } 26 } 27 } 28 } 29 }) 30 } 31}

Pattern 3: Assertion Helper

typescript
1// Service helper method 2private async assertExists(siteId: string, id: string): Promise<void> { 3 const asset = await this.assetsRepo.findById(id, siteId, { id: true }) 4 if (!asset) { 5 throw new NotFoundException('Asset not found') 6 } 7} 8 9// Usage 10async update(siteId: string, id: string, dto: UpdateAssetDto) { 11 await this.assertExists(siteId, id) // Throws if not found 12 return this.assetsRepo.update(id, { /* ... */ }) 13}

When NOT to Use Repository

  • read-only utilities: Simple helper functions that don't need injection
  • One-off scripts: Migration scripts or seeders (can use Prisma directly)
  • ListService delegate: List/pagination queries can pass Prisma delegate to ListService

Migration Checklist

When refactoring existing code to use repositories:

  1. ✅ Create repository file in repositories/ folder
  2. ✅ Move all Prisma queries from service to repository
  3. ✅ Add transaction support (tx?: Prisma.TransactionClient) to all methods
  4. ✅ Make repositories return null for not-found cases
  5. ✅ Update service to inject repository
  6. ✅ Add HTTP exceptions in service layer
  7. ✅ Update module to provide/export repository
  8. ✅ Verify no direct Prisma calls remain in service
  9. ✅ Check cross-module dependencies (import correct module)
  10. ✅ Run tests and check for compilation errors
  • See apps/api-app/REFACTORING_SUMMARY.md for implementation details
  • See apps/api-app/ARCHITECTURE.md for module structure
  • See docs/ARCHITECTURE.md for overall system architecture

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is nestjs-repository-pattern?

Perfect for Full-Stack Agents needing clean architecture guidelines for NestJS applications with Prisma ORM nestjs-repository-pattern is a set of guidelines for implementing the repository pattern in NestJS applications, focusing on clean architecture and database access with Prisma ORM.

How do I install nestjs-repository-pattern?

Run the command: npx killer-skills add Just-DX/maintenance-management-system/nestjs-repository-pattern. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for nestjs-repository-pattern?

Key use cases include: Implementing data access layers for User, Asset, and Site entities, Refactoring services to remove direct Prisma/DB calls, Setting up transaction support for NestJS applications, Organizing code for testability and maintainability.

Which IDEs are compatible with nestjs-repository-pattern?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for nestjs-repository-pattern?

Requires NestJS and Prisma ORM setup. Limited to NestJS applications.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add Just-DX/maintenance-management-system/nestjs-repository-pattern. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use nestjs-repository-pattern immediately in the current project.

Related Skills

Looking for an alternative to nestjs-repository-pattern or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI