ワンクリックで
state-view-slice
Generate Marten read models, projections, and Wolverine HTTP GET endpoints for STATE_VIEW slices
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Generate Marten read models, projections, and Wolverine HTTP GET endpoints for STATE_VIEW slices
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Generate event-driven automation processors for AUTOMATION slices using Wolverine message handlers
Transform slice definitions from config.json into C# code using Wolverine + Marten (Critter Stack)
Generate commands, events, aggregates, Wolverine HTTP endpoints (POST), and tests for STATE_CHANGE slices
Generate translators that map external events (from other bounded contexts or systems) into internal domain events using Wolverine handlers
| name | state-view-slice |
| description | Generate Marten read models, projections, and Wolverine HTTP GET endpoints for STATE_VIEW slices |
A STATE_VIEW slice projects event data into Marten read model documents. It generates:
IDocument) in <Context>/Slices/<SliceName>SingleStreamProjection or MultiStreamProjection) in Internal/<Context>/Slices/<SliceName>Note: STATE_VIEW slices do NOT contain commands or events. Events come from STATE_CHANGE slices.
Events (from STATE_CHANGE) → Marten Projection → ReadModel document → Wolverine GET endpoint
| Java / Axon | C# / Critter Stack |
|---|---|
@Entity JPA class | Marten document class |
JpaRepository | IQuerySession.LoadAsync<T>() |
@EventHandler Projector | Marten SingleStreamProjection<T> |
@QueryHandler | Direct query in GET endpoint |
QueryGateway.query() | IQuerySession.LoadAsync<T>() |
Flyway migration | Marten auto-creates schema |
ProjectionLifecycle.Async | ProjectionLifecycle.Async |
ProjectionLifecycle.Inline | ProjectionLifecycle.Inline |
Location: <Context>/Slices/<SliceName>/<SliceName>ReadModel.cs
using SlicingWorkshop.Common;
namespace SlicingWorkshop.<Context>.Slices.<SliceName>;
public class <SliceName>ReadModel : IReadModel
{
public Guid Id { get; set; }
public <Type> <FieldName> { get; set; }
// Add fields from readmodel definition
}
Location: <Context>/Slices/<SliceName>/Internal/<SliceName>Projection.cs
Single stream (one aggregate):
using Marten.Events.Aggregation;
using SlicingWorkshop.Events;
namespace SlicingWorkshop.<Context>.Slices.<SliceName>.Internal;
public class <SliceName>Projection : SingleStreamProjection<<SliceName>ReadModel>
{
public void Apply(<EventName> @event, <SliceName>ReadModel readModel)
{
readModel.Id = @event.AggregateId;
// Map event fields to read model fields
}
}
Multi-stream:
using Marten.Events.Aggregation;
using SlicingWorkshop.Events;
namespace SlicingWorkshop.<Context>.Slices.<SliceName>.Internal;
public class <SliceName>Projection : MultiStreamProjection<<SliceName>ReadModel, Guid>
{
public <SliceName>Projection()
{
Identity<<EventName>>(e => e.AggregateId);
}
public void Apply(<EventName> @event, <SliceName>ReadModel readModel)
{
readModel.Id = @event.AggregateId;
// Map fields
}
}
Add to the AddMarten options in Program.cs:
opts.Projections.Add<<SliceName>Projection>(ProjectionLifecycle.Async);
// or Inline for synchronous updates
Location: <Context>/Slices/<SliceName>/<SliceName>Endpoint.cs
using Marten;
using Wolverine.Http;
namespace SlicingWorkshop.<Context>.Slices.<SliceName>;
public static class <SliceName>Endpoint
{
[WolverineGet("/api/<context>/<resource>/{id}")]
public static async Task<<SliceName>ReadModel?> Get(
Guid id,
IQuerySession session)
{
return await session.LoadAsync<<SliceName>ReadModel>(id);
}
}
Location: <Context>/Slices/<SliceName>/Tests/<SliceName>ProjectionTests.cs
using Marten;
using SlicingWorkshop.Events;
using Xunit;
namespace SlicingWorkshop.<Context>.Slices.<SliceName>.Tests;
public class <SliceName>ProjectionTests : IClassFixture<AppFixture>
{
private readonly AppFixture _fixture;
public <SliceName>ProjectionTests(AppFixture fixture) => _fixture = fixture;
[Fact]
public async Task <SpecTitleAsPascalCase>()
{
var aggregateId = Guid.NewGuid();
// Apply events directly to the event store
using var session = _fixture.Store.LightweightSession();
session.Events.Append(aggregateId, new <EventName>(aggregateId /*, fields */));
await session.SaveChangesAsync();
// Wait for async projection (or use Inline)
await _fixture.Store.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(5));
using var querySession = _fixture.Store.QuerySession();
var result = await querySession.LoadAsync<<SliceName>ReadModel>(aggregateId);
Assert.NotNull(result);
// Assert field values
}
}
| config.json Type | C# Type | Marten notes |
|---|---|---|
| UUID | Guid | Default Id type |
| String | string | |
| Date | DateOnly | |
| Integer | int | |
| Boolean | bool | |
| Decimal | decimal | |
| Multiple cardinality | List | Initialize in constructor |
| optional: true | T? |
ProjectionLifecycle.Inline for strongly consistent reads (same transaction)ProjectionLifecycle.Async for eventually consistent, high-throughput projectionsnull → Wolverine HTTP maps to 404 automatically