# Abp Development Flow

> ABP development workflow - step-by-step guide for adding new entities, migrations, application services, localization, permissions, and tests. Use when adding new features or entities to an ABP project.

- Skill: `majiayu000/abp-development-flow` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/abp-development-flow`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/abp-development-flow/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/abp-development-flow

---


# ABP Development Workflow

> **Tutorials**: https://abp.io/docs/latest/tutorials

## Adding a New Entity (Full Flow)

### 1. Domain Layer
Create entity (location varies by template: `*.Domain/Entities/` for layered, `Entities/` for single-layer/microservice):

```csharp
public class Book : AggregateRoot<Guid>
{
    public string Name { get; private set; }
    public decimal Price { get; private set; }
    public Guid AuthorId { get; private set; }

    protected Book() { }

    public Book(Guid id, string name, decimal price, Guid authorId) : base(id)
    {
        Name = Check.NotNullOrWhiteSpace(name, nameof(name));
        SetPrice(price);
        AuthorId = authorId;
    }

    public void SetPrice(decimal price)
    {
        Price = Check.Range(price, nameof(price), 0, 9999);
    }
}
```

### 2. Domain.Shared
Add constants and enums in `*.Domain.Shared/`:

```csharp
public static class BookConsts
{
    public const int MaxNameLength = 128;
}

public enum BookType
{
    Novel,
    Science,
    Biography
}
```

### 3. Repository Interface (Optional)
Define custom repository in `*.Domain/` only if you need custom query methods. For simple CRUD, use generic `IRepository<Book, Guid>` directly:

```csharp
// Only if custom queries are needed
public interface IBookRepository : IRepository<Book, Guid>
{
    Task<Book> FindByNameAsync(string name);
}
```

### 4. EF Core Configuration
In `*.EntityFrameworkCore/`:

**DbContext:**
```csharp
public DbSet<Book> Books { get; set; }
```

**OnModelCreating:**
```csharp
builder.Entity<Book>(b =>
{
    b.ToTable(MyProjectConsts.DbTablePrefix + "Books", MyProjectConsts.DbSchema);
    b.ConfigureByConvention();
    b.Property(x => x.Name).IsRequired().HasMaxLength(BookConsts.MaxNameLength);
    b.HasIndex(x => x.Name);
});
```

**Repository Implementation (only if custom interface defined):**
```csharp
public class BookRepository : EfCoreRepository<MyDbContext, Book, Guid>, IBookRepository
{
    public BookRepository(IDbContextProvider<MyDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }

    public async Task<Book> FindByNameAsync(string name)
    {
        return await (await GetDbSetAsync())
            .FirstOrDefaultAsync(b => b.Name == name);
    }
}
```

### 5. Run Migration
See `abp-ef-core` skill for migration commands. Recommended: use `DbMigrator` project to apply migrations and seed data.

### 6. Application.Contracts
Create DTOs and service interface:

```csharp
// DTOs
public class BookDto : EntityDto<Guid>
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public Guid AuthorId { get; set; }
}

public class CreateBookDto
{
    [Required]
    [StringLength(BookConsts.MaxNameLength)]
    public string Name { get; set; }

    [Range(0, 9999)]
    public decimal Price { get; set; }

    [Required]
    public Guid AuthorId { get; set; }
}

// Service Interface
public interface IBookAppService : IApplicationService
{
    Task<BookDto> GetAsync(Guid id);
    Task<PagedResultDto<BookDto>> GetListAsync(PagedAndSortedResultRequestDto input);
    Task<BookDto> CreateAsync(CreateBookDto input);
}
```

### 7. Object Mapping (Mapperly / AutoMapper)
ABP supports both Mapperly and AutoMapper. Prefer the provider already used in the solution.

If the solution uses **Mapperly**, create a mapper in the Application project:

```csharp
[Mapper]
public partial class BookMapper
{
    public partial BookDto MapToDto(Book book);
    public partial List<BookDto> MapToDtoList(List<Book> books);
}
```

Register in module:
```csharp
context.Services.AddSingleton<BookMapper>();
```

### 8. Application Service
Implement service (using generic repository - use `IBookRepository` if you defined custom interface in step 3):

```csharp
public class BookAppService : ApplicationService, IBookAppService
{
    private readonly IRepository<Book, Guid> _bookRepository; // Or IBookRepository
    private readonly BookMapper _bookMapper;

    public BookAppService(
        IRepository<Book, Guid> bookRepository,
        BookMapper bookMapper)
    {
        _bookRepository = bookRepository;
        _bookMapper = bookMapper;
    }

    public async Task<BookDto> GetAsync(Guid id)
    {
        var book = await _bookRepository.GetAsync(id);
        return _bookMapper.MapToDto(book);
    }

    [Authorize(MyProjectPermissions.Books.Create)]
    public async Task<BookDto> CreateAsync(CreateBookDto input)
    {
        var book = new Book(
            GuidGenerator.Create(),
            input.Name,
            input.Price,
            input.AuthorId
        );

        await _bookRepository.InsertAsync(book);
        return _bookMapper.MapToDto(book);
    }
}
```

### 9. Add Localization
In `*.Domain.Shared/Localization/*/en.json`:

```json
{
  "Book": "Book",
  "Books": "Books",
  "BookName": "Name",
  "BookPrice": "Price"
}
```

### 10. Add Permissions (if needed)
```csharp
public static class MyProjectPermissions
{
    public static class Books
    {
        public const string Default = "MyProject.Books";
        public const string Create = Default + ".Create";
    }
}
```

### 11. Add Tests
```csharp
public class BookAppService_Tests : MyProjectApplicationTestBase
{
    private readonly IBookAppService _bookAppService;

    public BookAppService_Tests()
    {
        _bookAppService = GetRequiredService<IBookAppService>();
    }

    [Fact]
    public async Task Should_Create_Book()
    {
        var result = await _bookAppService.CreateAsync(new CreateBookDto
        {
            Name = "Test Book",
            Price = 19.99m
        });

        result.Id.ShouldNotBe(Guid.Empty);
        result.Name.ShouldBe("Test Book");
    }
}
```

## Checklist for New Features

- [ ] Entity created with proper constructors
- [ ] Constants in Domain.Shared
- [ ] Custom repository interface in Domain (only if custom queries needed)
- [ ] EF Core configuration added
- [ ] Custom repository implementation (only if interface defined)
- [ ] Migration generated and applied (use DbMigrator)
- [ ] Mapperly mapper created and registered
- [ ] DTOs created in Application.Contracts
- [ ] Service interface defined
- [ ] Service implementation with authorization
- [ ] Localization keys added
- [ ] Permissions defined (if applicable)
- [ ] Tests written

