Skip to main content

state-change-slice

Knows how to build state change slices

Source facts

Repository
dilgerma/ralph-loop-demo
Last source activity
March 11, 2026 at 16:29
Detected SKILL.md language
English
Stars
1
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
state change slice
description
Knows how to build state change slices
# STATE_CHANGE Slice Skill ## Overview A STATE_CHANGE slice represents a business operation that modifies aggregate state through commands and events. This is the core CQRS/Event Sourcing pattern. ## Input Structure ```json { "sliceType": "STATE_CHANGE", "title": "slice: <Name>", "context": "<BoundedContext>", "commands": [...], "events": [...], "readmodels": [...], "screens": [...], "processors": [...], "specifications": [...] } ``` ## Flow Pattern ``` Screen (UI) → Command → Aggregate (@CommandHandler) → Event → ReadModel (via @EventHandler Projector) ↓ Automation (if processors exist) ``` ## Code Generation Steps ### Step 1: Create Command **Location:** `src/main/kotlin/de/alex/<module>/domain/commands/<commandname>/<CommandName>Command.kt` **Template:** ```kotlin package de.alex.<module>.domain.commands.<commandname> import de.alex.common.Command import org.axonframework.modelling.command.TargetAggregateIdentifier import java.util.UUID data class <CommandName>Command( @TargetAggregateIdentifier var aggregateId: UUID, // Add fields from slice command definition // Map types: UUID, String, Date → LocalDate, Integer → Int, Boolean, Decimal → BigDecimal // Handle cardinality: Single → regular type, Multiple → List<type> ) : Command ``` **Field Mapping Rules:** | Slice Type | Kotlin Type | |------------|-------------| | UUID | UUID | | String | String | | Date | LocalDate | | Integer | Int | | Boolean | Boolean | | Decimal | BigDecimal | | Multiple cardinality | List<T> | | optional: true | Nullable (T?) | ### Step 2: Create Event(s) **Location:** `src/main/kotlin/de/alex/events/<EventName>Event.kt` **Template:** ```kotlin package de.alex.events import de.alex.common.Event import java.util.UUID data class <EventName>Event( var aggregateId: UUID, // Add fields from slice event definition // Fields typically mirror command fields ) : Event ``` ### Step 3: Add CommandHandler to Aggregate **Location:** `src/main/kotlin/de/alex/domain/<Aggregate>Aggregate.kt` **Template for existing aggregate:** ```kotlin @CommandHandler fun handle(command: <CommandName>Command): CommandResult { // Business validation logic AggregateLifecycle.apply( <EventName>Event( command.aggregateId, // Map command fields to event fields ) ) return CommandResult(command.aggregateId.toString(), AggregateLifecycle.getVersion()) } ``` **Template for new aggregate creation (when createsAggregate: true):** ```kotlin @CreationPolicy(AggregateCreationPolicy.ALWAYS) @CommandHandler fun handle(command: <CommandName>Command): CommandResult { AggregateLifecycle.apply( <EventName>Event( command.aggregateId, // Map command fields to event fields ) ) return CommandResult(command.aggregateId.toString(), AggregateLifecycle.getVersion()) } ``` ### Step 4: Add EventSourcingHandler to Aggregate ```kotlin @EventSourcingHandler fun on(event: <EventName>Event) { // Update aggregate state from event this.aggregateId = event.aggregateId // Update other state fields } ``` ## Example: Processing "slice: Assign Clerk to Case" **Input:** ```json { "sliceType": "STATE_CHANGE", "title": "slice: Assign Clerk to Case", "commands": [{ "title": "Assign Clerk to Case", "aggregate": "Case", "fields": [ {"name": "caseId", "type": "UUID", "idAttribute": true}, {"name": "clerkId", "type": "UUID"}, {"name": "hourlyRate", "type": "Decimal"} ] }], "events": [{ "title": "Clerk Assigned to Case", "fields": [...] }] } ``` **Generated Files:** 1. `src/main/kotlin/de/alex/cases/domain/commands/assignclerktocase/AssignClerkToCaseCommand.kt` 2. `src/main/kotlin/de/alex/events/ClerkAssignedToCaseEvent.kt` 3. Update `src/main/kotlin/de/alex/domain/CaseAggregate.kt` with handlers ## Processing Group Configuration Ensure the module has a ProcessingGroups file: **Location:** `src/main/kotlin/de/alex/<module>/ProcessingGroups.kt` ```kotlin package de.alex.<module> class ProcessingGroups { companion object { const val <MODULE> = "<MODULE>" } } ```
View on GitHub