🎯

easyplatform-backend

🎯Skill

from duc01226/easyplatform

VibeIndex|
What it does

Develops comprehensive backend components for .NET microservices using EasyPlatform's CQRS, domain-driven design, and modular architecture patterns.

easyplatform-backend

Installation

Install skill:
npx skills add https://github.com/duc01226/easyplatform --skill easyplatform-backend
6
AddedJan 27, 2026

Skill Details

SKILL.md

Complete Easy.Platform backend development for EasyPlatform. Covers CQRS commands/queries, entities, validation, migrations, background jobs, and message bus. Use for any .NET backend task in this monorepo.

Overview

# Easy.Platform Backend Development

Complete backend development patterns for EasyPlatform .NET 9 microservices.

Quick Decision Tree

```

[Backend Task]

β”œβ”€β”€ API endpoint?

β”‚ β”œβ”€β”€ Creates/Updates/Deletes data β†’ CQRS Command (Β§1)

β”‚ └── Reads data β†’ CQRS Query (Β§2)

β”œβ”€β”€ Business entity? β†’ Entity Development (Β§3)

β”œβ”€β”€ Side effects (notifications, emails)? β†’ Entity Event Handler (Β§4) - NEVER in command handlers!

β”œβ”€β”€ Data transformation/backfill? β†’ Migration (Β§5)

β”œβ”€β”€ Scheduled/recurring task? β†’ Background Job (Β§6)

└── Cross-service sync? β†’ Message Bus (Β§7) - NEVER direct DB access!

```

File Organization

```

{Service}.Application/

β”œβ”€β”€ UseCaseCommands/{Feature}/Save{Entity}Command.cs # Command+Handler+Result

β”œβ”€β”€ UseCaseQueries/{Feature}/Get{Entity}ListQuery.cs # Query+Handler+Result

β”œβ”€β”€ UseCaseEvents/{Feature}/*EntityEventHandler.cs # Side effects

β”œβ”€β”€ BackgroundJobs/{Feature}/*Job.cs # Scheduled tasks

β”œβ”€β”€ MessageBusProducers/*Producer.cs # Outbound events

β”œβ”€β”€ MessageBusConsumers/{Entity}/*Consumer.cs # Inbound events

└── DataMigrations/*DataMigration.cs # Data migrations

{Service}.Domain/

└── Entities/{Entity}.cs # Domain entities

```

Critical Rules

  1. Repository: IPlatformQueryableRootRepository -- NEVER throw exceptions for validation
  2. Validation: PlatformValidationResult fluent API
  3. Side Effects: Entity Event Handlers -- NEVER in command handlers
  4. DTO Mapping: DTOs own mapping via PlatformEntityDto.MapToEntity()
  5. Cross-Service: Message bus -- NEVER direct database access

---

Β§1. CQRS Commands

File: UseCaseCommands/{Feature}/Save{Entity}Command.cs (Command + Result + Handler in ONE file)

```csharp

public sealed class SaveEmployeeCommand : PlatformCqrsCommand

{

public string? Id { get; set; }

public string Name { get; set; } = "";

public override PlatformValidationResult Validate()

=> base.Validate().And(_ => Name.IsNotNullOrEmpty(), "Name required");

}

public sealed class SaveEmployeeCommandResult : PlatformCqrsCommandResult

{

public EmployeeDto Entity { get; set; } = null!;

}

internal sealed class SaveEmployeeCommandHandler :

PlatformCqrsCommandApplicationHandler

{

protected override async Task HandleAsync(

SaveEmployeeCommand req, CancellationToken ct)

{

var entity = req.Id.IsNullOrEmpty()

? req.MapToNewEntity().With(e => e.CreatedBy = RequestContext.UserId())

: await repository.GetByIdAsync(req.Id, ct)

.EnsureFound().Then(e => req.UpdateEntity(e));

await entity.ValidateAsync(repository, ct).EnsureValidAsync();

await repository.CreateOrUpdateAsync(entity, ct);

return new SaveEmployeeCommandResult { Entity = new EmployeeDto(entity) };

}

}

```

⚠️ MUST READ: [references/cqrs-patterns.md](references/cqrs-patterns.md) β€” full CQRS command patterns

---

Β§2. CQRS Queries

File: UseCaseQueries/{Feature}/Get{Entity}ListQuery.cs

```csharp

public sealed class GetEmployeeListQuery : PlatformCqrsPagedQuery

{

public List Statuses { get; set; } = [];

public string? SearchText { get; set; }

}

internal sealed class GetEmployeeListQueryHandler :

PlatformCqrsQueryApplicationHandler

{

protected override async Task HandleAsync(

GetEmployeeListQuery req, CancellationToken ct)

{

var qb = repository.GetQueryBuilder((uow, q) => q

.Where(e => e.CompanyId == RequestContext.CurrentCompanyId())

.WhereIf(req.Statuses.Any(), e => req.Statuses.Contains(e.Status))

.PipeIf(req.SearchText.IsNotNullOrEmpty(), q =>

searchService.Search(q, req.SearchText, Employee.DefaultFullTextSearchColumns())));

var (total, items) = await (

repository.CountAsync((uow, q) => qb(uow, q), ct),

repository.GetAllAsync((uow, q) => qb(uow, q)

.OrderByDescending(e => e.CreatedDate).PageBy(req.SkipCount, req.MaxResultCount), ct)

);

return new GetEmployeeListQueryResult(items.SelectList(e => new EmployeeDto(e)), total, req);

}

}

```

⚠️ MUST READ: [references/cqrs-patterns.md](references/cqrs-patterns.md) β€” full CQRS query patterns

---

Β§3. Entity Development

File: {Service}.Domain/Entities/{Entity}.cs

```csharp

[TrackFieldUpdatedDomainEvent]

public sealed class Employee : RootAuditedEntity

{

[TrackFieldUpdatedDomainEvent] public string Name { get; set; } = "";

public string CompanyId { get; set; } = "";

[ComputedEntityProperty]

public string DisplayName { get => $"{Code} - {Name}"; set { } }

public static Expression> OfCompanyExpr(string companyId) => e => e.CompanyId == companyId;

public static Expression> UniqueExpr(string companyId, string code) => e => e.CompanyId == companyId && e.Code == code;

public static Expression>[] DefaultFullTextSearchColumns() => [e => e.Name, e => e.Code];

public async Task ValidateAsync(IRepository repo, CancellationToken ct)

=> await PlatformValidationResult.Valid()

.And(() => Name.IsNotNullOrEmpty(), "Name required")

.AndNotAsync(() => repo.AnyAsync(e => e.Id != Id && e.Code == Code, ct), "Code exists");

}

```

⚠️ MUST READ: [references/entity-patterns.md](references/entity-patterns.md) β€” full entity patterns

---

Β§4. Entity Event Handlers (Side Effects)

CRITICAL: NEVER call side effects in command handlers!

File: UseCaseEvents/{Feature}/Send{Action}On{Event}{Entity}EntityEventHandler.cs

```csharp

internal sealed class SendNotificationOnCreateEmployeeEntityEventHandler

: PlatformCqrsEntityEventApplicationHandler

{

public override async Task HandleWhen(PlatformCqrsEntityEvent @event)

=> !@event.RequestContext.IsSeedingTestingData()

&& @event.CrudAction == PlatformCqrsEntityEventCrudAction.Created;

protected override async Task HandleAsync(PlatformCqrsEntityEvent @event, CancellationToken ct)

=> await notificationService.SendAsync(@event.EntityData.Id);

}

```

⚠️ MUST READ: [references/side-effects-patterns.md](references/side-effects-patterns.md) β€” side effects patterns

Β§5-7. Migrations, Jobs, Message Bus

⚠️ MUST READ: [migration-patterns.md](references/migration-patterns.md) | [job-patterns.md](references/job-patterns.md) | [messaging-patterns.md](references/messaging-patterns.md)

---

Anti-Patterns

| Don't | Do |

| --------------------------------- | ----------------------------------------------- |

| throw new ValidationException() | PlatformValidationResult fluent API |

| Side effects in command handler | Entity Event Handler in UseCaseEvents/ |

| Direct cross-service DB access | Message bus |

| DTO mapping in handler | PlatformEntityDto.MapToEntity() |

| Separate Command/Handler files | ONE file: Command + Result + Handler |

| protected bool HandleWhen() | public override async Task HandleWhen() |

Checklist

  • [ ] Service-specific repository, fluent validation (.And(), .AndAsync())
  • [ ] No side effects in command handlers, DTO mapping in DTO class
  • [ ] Cross-service uses message bus, jobs have maxConcurrent, migrations use dismissSendEvent: true

IMPORTANT Task Planning Notes

  • Always plan and break many small todo tasks
  • Always add a final review todo task to review the works done at the end to find any fix or enhancement needed

More from this repository10

🎯
qa-engineer🎯Skill

Generates comprehensive test plans, test cases, and coverage analysis to support QA engineers in systematic software testing and quality assurance.

🎯
learn🎯Skill

Teaches Claude new patterns, preferences, and conventions to remember across coding sessions using explicit learning commands.

🎯
product-owner🎯Skill

Helps Product Owners prioritize ideas, manage backlogs, and communicate product vision through structured decision-making frameworks.

🎯
pdf-to-markdown🎯Skill

pdf-to-markdown skill from duc01226/easyplatform

🎯
business-feature-docs🎯Skill

Generates comprehensive enterprise module documentation with a 26-section structure, creating detailed specs and folder hierarchy for business features.

🎯
readme-improvement🎯Skill

readme-improvement skill from duc01226/easyplatform

🎯
learned-patterns🎯Skill

Manages Claude's learned patterns by listing, viewing, archiving, and dynamically adjusting pattern confidence levels.

🎯
arch-performance-optimization🎯Skill

Optimizes system performance by triaging and routing to specific strategies for database, frontend, API, jobs, and cross-service bottlenecks.

🎯
plan-analysis🎯Skill

Analyzes implementation plans by extracting features, assessing change impacts, mapping specifications, and preparing comprehensive technical and business impact reports.

🎯
frontend-angular-form🎯Skill

Generates Angular reactive forms with advanced validation, async validators, dependent validation, and FormArrays using platform-specific design patterns.