Claude-skill-registry create-repository
Create repository interface for data access abstraction. Use when adding a new resource that needs database operations, defining CRUD interface, or setting up repository pattern. Triggers on "new repository", "repository interface", "data access layer", "create repository".
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/create-repository" ~/.claude/skills/majiayu000-claude-skill-registry-create-repository && rm -rf "$T"
skills/data/create-repository/SKILL.mdCreate Repository Interface
Creates the repository interface that defines data access operations for an entity. Implementations (MockDB, MongoDB, etc.) will implement this interface.
Quick Reference
Location:
src/repositories/{entity-name}.repository.ts
Naming: Singular, kebab-case (e.g., note.repository.ts, course.repository.ts)
Instructions
Step 1: Create the Interface File
Create
src/repositories/{entity-name}.repository.ts
Step 2: Import Schema Types
import type { {Entity}Type, Create{Entity}Type, Update{Entity}Type, {Entity}QueryParamsType, {Entity}IdType, } from "@/schemas/{entity-name}.schema"; import type { PaginatedResultType } from "@/schemas/shared.schema"; import type { UserIdType } from "@/schemas/user.schemas";
Step 3: Define the Interface
export interface I{Entity}Repository { findAll(params: {Entity}QueryParamsType): Promise<PaginatedResultType<{Entity}Type>>; findById(id: {Entity}IdType): Promise<{Entity}Type | null>; create(data: Create{Entity}Type, createdByUserId: UserIdType): Promise<{Entity}Type>; update(id: {Entity}IdType, data: Update{Entity}Type): Promise<{Entity}Type | null>; remove(id: {Entity}IdType): Promise<boolean>; }
Standard CRUD Methods
Every repository interface should include these standard CRUD methods:
| Method | Parameters | Returns | Description |
|---|---|---|---|
| | | List with pagination/filtering |
| | | Single entity or null |
| | | Create and return new entity |
| | | Update and return, or null |
| | | True if deleted |
Patterns & Rules
Naming Conventions
- Interface name:
(e.g.,I{Entity}Repository
,INoteRepository
)ICourseRepository - File name:
(singular, kebab-case){entity-name}.repository.ts
Return Type Patterns
- Single entity lookups: Return
(null if not found)EntityType | null - List operations: Return
(always, even if empty)PaginatedResultType<EntityType> - Create operations: Return the created
(with generated ID and timestamps)EntityType - Update operations: Return
(null if entity doesn't exist)EntityType | null - Delete operations: Return
(true if deleted, false if not found)boolean
Parameter Patterns
- Create method: Takes
+Create{Entity}TypecreatedByUserId: UserIdType - Update method: Takes
separately (from URL) +id
(from body)Update{Entity}Type - Query methods: Take
for filtering/pagination{Entity}QueryParamsType
Import Rules
- Always use path aliases:
,@/schemas/...@/repositories/... - Import types with
for type-only importsimport type { ... } - Import from specific schema files, not barrel exports
Adding Custom Methods
Add custom methods based on your system's requirements. Common patterns include:
Query by Attribute (findByX
)
findByXFind entities by a specific attribute:
findByStatus(status: StatusType, params: {Entity}QueryParamsType): Promise<PaginatedResultType<{Entity}Type>>; findByOwner(ownerId: UserIdType, params: {Entity}QueryParamsType): Promise<PaginatedResultType<{Entity}Type>>; findByCategory(categoryId: CategoryIdType, params: {Entity}QueryParamsType): Promise<PaginatedResultType<{Entity}Type>>;
Batch Operations
Operate on multiple entities at once:
// Batch queries findAllByIds(ids: {Entity}IdType[], params: {Entity}QueryParamsType): Promise<PaginatedResultType<{Entity}Type>>; findAllByStatus(status: StatusType, params: {Entity}QueryParamsType): Promise<PaginatedResultType<{Entity}Type>>; // Batch mutations createMany(data: Create{Entity}Type[], createdByUserId: UserIdType): Promise<{Entity}Type[]>; updateMany(ids: {Entity}IdType[], data: Update{Entity}Type): Promise<number>; // returns count updated removeMany(ids: {Entity}IdType[]): Promise<number>; // returns count deleted removeByOwner(ownerId: UserIdType): Promise<number>; // returns count deleted
Aggregation Operations
Get counts or summaries without fetching full entities:
countByStatus(status: StatusType): Promise<number>; countByOwner(ownerId: UserIdType): Promise<number>;
Complete Example
import type { NoteType, CreateNoteType, UpdateNoteType, NoteQueryParamsType, NoteIdType, } from "@/schemas/note.schema"; import type { PaginatedResultType } from "@/schemas/shared.schema"; import type { UserIdType } from "@/schemas/user.schemas"; export interface INoteRepository { // Standard CRUD findAll(params: NoteQueryParamsType): Promise<PaginatedResultType<NoteType>>; findById(id: NoteIdType): Promise<NoteType | null>; create(data: CreateNoteType, createdByUserId: UserIdType): Promise<NoteType>; update(id: NoteIdType, data: UpdateNoteType): Promise<NoteType | null>; remove(id: NoteIdType): Promise<boolean>; // Custom methods (assuming it was needed) findAllByIds( ids: NoteIdType[], params: NoteQueryParamsType, ): Promise<PaginatedResultType<NoteType>>; }
Next Steps
After creating the interface, create an implementation:
- For development/testing: Use
skillcreate-mockdb-repository - For production: Use
skillcreate-mongodb-repository
What NOT to Do
- Do NOT include implementation details in the interface
- Do NOT use concrete types (use the interface for dependency injection)
- Do NOT add business logic - repositories only handle data access
- Do NOT throw domain errors - return null/false and let the service handle it
- Do NOT use plural naming (
) - use singular (notes.repository.ts
)note.repository.ts