From acc
Generates PHP 8.4 Event Store for event sourcing with Doctrine DBAL implementation, event streams, stored events, optimistic locking, version tracking, and unit tests. For audit trails, event replay, and temporal queries.
How this skill is triggered — by the user, by Claude, or both
Slash command
/acc:create-event-storeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Creates Event Store infrastructure for event sourcing with aggregate history and event replay.
Creates Event Store infrastructure for event sourcing with aggregate history and event replay.
| Scenario | Example |
|---|---|
| Event sourcing | Aggregate state from events |
| Audit trail | Complete change history |
| Event replay | Rebuild projections from events |
| Temporal queries | Query state at any point in time |
Path: src/Domain/{BoundedContext}/EventStore/
StoredEvent.php — Immutable stored event value objectEventStreamInterface.php — Event stream contractEventStream.php — Event stream implementationEventStoreInterface.php — Event store contractPath: src/Infrastructure/{BoundedContext}/EventStore/
DoctrineEventStore.php — Doctrine DBAL implementation with optimistic lockingStoredEventTest.php — Stored event immutability testsEventStreamTest.php — Stream operations testsDoctrineEventStoreTest.php — Integration tests| Component | Path |
|---|---|
| StoredEvent | src/Domain/{BoundedContext}/EventStore/ |
| EventStream | src/Domain/{BoundedContext}/EventStore/ |
| EventStoreInterface | src/Domain/{BoundedContext}/EventStore/ |
| DoctrineEventStore | src/Infrastructure/{BoundedContext}/EventStore/ |
| Unit Tests | tests/Unit/Domain/{BoundedContext}/EventStore/ |
| Integration Tests | tests/Integration/Infrastructure/{BoundedContext}/EventStore/ |
| Component | Pattern | Example |
|---|---|---|
| Stored Event | StoredEvent | StoredEvent |
| Stream Interface | EventStreamInterface | EventStreamInterface |
| Stream | EventStream | EventStream |
| Store Interface | EventStoreInterface | EventStoreInterface |
| Store Impl | Doctrine{Name}EventStore | DoctrineEventStore |
| Exception | ConcurrencyException | ConcurrencyException |
| Test | {ClassName}Test | StoredEventTest |
final readonly class StoredEvent
{
public function __construct(
public string $aggregateId,
public string $aggregateType,
public string $eventType,
public string $payload,
public int $version,
public \DateTimeImmutable $createdAt
) {}
public static function fromDomainEvent(string $aggregateId, string $aggregateType, int $version, object $event): self;
public function toArray(): array;
public static function fromArray(array $data): self;
}
interface EventStoreInterface
{
public function append(string $aggregateId, EventStream $events, int $expectedVersion): void;
public function load(string $aggregateId): EventStream;
public function loadFromVersion(string $aggregateId, int $fromVersion): EventStream;
}
final class EventStream implements \IteratorAggregate, \Countable
{
public static function empty(): self;
public static function fromEvents(array $events): self;
public function append(StoredEvent $event): self;
public function getVersion(): int;
public function isEmpty(): bool;
public function getIterator(): \ArrayIterator;
public function count(): int;
}
// Append events
$events = EventStream::fromEvents([
StoredEvent::fromDomainEvent($orderId, 'Order', 1, $orderCreated),
StoredEvent::fromDomainEvent($orderId, 'Order', 2, $itemAdded),
]);
$eventStore->append($orderId, $events, expectedVersion: 0);
// Load and replay
$stream = $eventStore->load($orderId);
foreach ($stream as $event) {
$aggregate->apply($event);
}
CREATE TABLE event_store (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
aggregate_id VARCHAR(36) NOT NULL,
aggregate_type VARCHAR(255) NOT NULL,
event_type VARCHAR(255) NOT NULL,
payload JSON NOT NULL,
version INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE INDEX idx_aggregate_version (aggregate_id, version),
INDEX idx_aggregate_type (aggregate_type),
INDEX idx_event_type (event_type),
INDEX idx_created_at (created_at)
);
| Anti-pattern | Problem | Solution |
|---|---|---|
| Mutable Events | History changes | Immutable StoredEvent |
| Missing Version | No optimistic locking | Version per aggregate |
| No Idempotency | Duplicate appends | Unique aggregate_id + version |
| Large Payloads | Slow reads | Serialize only essential data |
| No Snapshots | Slow rebuilds for long streams | Use create-snapshot |
| Global Stream Only | Can't load per-aggregate | Per-aggregate stream support |
For complete PHP templates and examples, see:
references/templates.md — StoredEvent, EventStream, EventStoreInterface, DoctrineEventStore templatesreferences/examples.md — Order event store usage and testsnpx claudepluginhub dykyi-roman/awesome-claude-code --plugin accGenerates PHP 8.4 snapshot infrastructure for event-sourced aggregates. Optimizes rebuild performance on long event streams via configurable strategies, Doctrine DBAL store, migrations, and unit tests.
Designs and implements event stores for event-sourced systems, covering architecture, requirements, tech comparisons (EventStoreDB, Postgres, Kafka), and scaling strategies.
Designs event store schemas and selects technologies for event-sourced systems. Covers PostgreSQL, EventStoreDB, Kafka, and DynamoDB patterns.