easyplatform-backend
π―Skillfrom duc01226/easyplatform
Develops comprehensive backend components for .NET microservices using EasyPlatform's CQRS, domain-driven design, and modular architecture patterns.
Installation
npx skills add https://github.com/duc01226/easyplatform --skill easyplatform-backendSkill Details
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
- Repository:
IPlatformQueryableRootRepository-- NEVER throw exceptions for validation - Validation:
PlatformValidationResultfluent API - Side Effects: Entity Event Handlers -- NEVER in command handlers
- DTO Mapping: DTOs own mapping via
PlatformEntityDto.MapToEntity() - 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
=> 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
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
public string? SearchText { get; set; }
}
internal sealed class GetEmployeeListQueryHandler :
PlatformCqrsQueryApplicationHandler
{
protected override async Task
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
public static Expression
public static Expression
public async Task
=> 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
=> !@event.RequestContext.IsSeedingTestingData()
&& @event.CrudAction == PlatformCqrsEntityEventCrudAction.Created;
protected override async Task HandleAsync(PlatformCqrsEntityEvent
=> 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 |
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 usedismissSendEvent: 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
Generates comprehensive test plans, test cases, and coverage analysis to support QA engineers in systematic software testing and quality assurance.
Teaches Claude new patterns, preferences, and conventions to remember across coding sessions using explicit learning commands.
Helps Product Owners prioritize ideas, manage backlogs, and communicate product vision through structured decision-making frameworks.
pdf-to-markdown skill from duc01226/easyplatform
Generates comprehensive enterprise module documentation with a 26-section structure, creating detailed specs and folder hierarchy for business features.
readme-improvement skill from duc01226/easyplatform
Manages Claude's learned patterns by listing, viewing, archiving, and dynamically adjusting pattern confidence levels.
Optimizes system performance by triaging and routing to specific strategies for database, frontend, API, jobs, and cross-service bottlenecks.
Analyzes implementation plans by extracting features, assessing change impacts, mapping specifications, and preparing comprehensive technical and business impact reports.
Generates Angular reactive forms with advanced validation, async validators, dependent validation, and FormArrays using platform-specific design patterns.