← Back to list

scaffold-aggregate
by aalmada
Full-stack .NET online book store application with event-sourced backend API and Blazor frontend, orchestrated by Aspire.
⭐ 13🍴 0📅 Jan 24, 2026
SKILL.md
name: scaffold-aggregate description: Create a new event-sourced aggregate with proper Apply methods, event handling, and Marten configuration. Use this when adding a new domain entity that needs event sourcing.
Follow this guide to create a new event-sourced aggregate in the ApiService following strict Event Sourcing patterns.
-
Define the Initial Event
- Create a
recordinsrc/BookStore.ApiService/Events/ - Naming: Past tense (e.g.,
AuthorCreated, notCreateAuthor) - Properties: Include all initial state properties
- IDs: Use
Guidfor aggregate ID - Timestamp: Use
DateTimeOffset - Example:
namespace BookStore.ApiService.Events; public record AuthorCreated( Guid Id, string Name, string Biography, DateTimeOffset CreatedAt );
- Create a
-
Create the Aggregate
- Create a
recordinsrc/BookStore.ApiService/Aggregates/ - Template:
namespace BookStore.ApiService.Aggregates; public record Author { public Guid Id { get; init; } public string Name { get; init; } = string.Empty; public string Biography { get; init; } = string.Empty; public bool Deleted { get; init; } public int Version { get; init; } // Factory method for new aggregates public static Author Create(AuthorCreated @event) { return new Author { Id = @event.Id, Name = @event.Name, Biography = @event.Biography }; } // Apply method for Marten (MUST be void, single parameter) public void Apply(AuthorCreated @event) { // Marten uses this for event replay - do not return anything } // Apply method for subsequent events public void Apply(AuthorUpdated @event) { // Handle state changes } }
- Create a
-
Add Behavior Methods
- Add methods to aggregate that return events
- Pattern: Validate → Return Event
- Example:
public AuthorUpdated Update(string name, string biography) { if (Deleted) throw new InvalidOperationException("Cannot update deleted author"); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Name is required", nameof(name)); return new AuthorUpdated(Id, name, biography, DateTimeOffset.UtcNow); }
-
Configure Marten
- Open
src/BookStore.ApiService/Program.cs - Add aggregate to Marten's event store:
builder.Services.AddMarten(options => { // Existing configuration... // Add your aggregate options.Events.StreamIdentity = StreamIdentity.AsGuid; });
- Open
-
Create Unit Tests
- Create test file in
tests/BookStore.ApiService.UnitTests/Aggregates/ - Test Pattern:
using TUnit.Core; using TUnit.Assertions.Extensions; public class AuthorTests { [Test] public async Task Create_ReturnsValidAggregate() { // Arrange var created = new AuthorCreated( Guid.CreateVersion7(), "Martin Fowler", "Author and speaker", DateTimeOffset.UtcNow ); // Act var author = Author.Create(created); // Assert await Assert.That(author.Id).IsEqualTo(created.Id); await Assert.That(author.Name).IsEqualTo("Martin Fowler"); } [Test] public async Task Update_DeletedAuthor_ThrowsException() { // Arrange var author = new Author { Deleted = true }; // Act & Assert await Assert.That(() => author.Update("New Name", "Bio")) .Throws<InvalidOperationException>(); } }
- Create test file in
-
Verify Analyzer Compliance
- Run
dotnet buildto check for BS1xxx-BS4xxx warnings - Ensure:
- ✅ Events are
recordtypes (BS1001) - ✅ Apply methods are
voidwith single parameter (BS1002) - ✅ Aggregates use proper patterns (BS2xxx)
- ✅ Events are
- Run
-
Next Steps
- Use
/scaffold-projectionto create read models from your aggregate's events - Use
/scaffold-writeto create complete command/handler/endpoint flow - Use
/scaffold-testto create integration tests - Use
/verify-featureto ensure everything works
- Use
Related Skills
Prerequisites:
- None - this is a foundational skill for event sourcing
Next Steps:
/scaffold-projection- Create read models from aggregate events/scaffold-write- Add commands, handlers, and endpoints for this aggregate/scaffold-test- Create integration tests/verify-feature- Run all verification checks
See Also:
- scaffold-write - Complete write operation workflow
- event-sourcing-guide - Event Sourcing patterns
- marten-guide - Marten event store integration
- analyzer-rules - Code analyzer rules (BS1xxx-BS4xxx)
- ApiService AGENTS.md - Backend patterns and conventions
Key Rules to Remember
- Apply Methods: MUST be
voidwith single event parameter (Marten convention) - Behavior Methods: Return events, don't mutate state directly
- IDs: Use
Guid.CreateVersion7()for new aggregates - Immutability: Use
recordtypes withinitproperties - Validation: Validate in behavior methods, throw exceptions for invalid operations
Score
Total Score
75/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
✓説明文
100文字以上の説明がある
+10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

