create-snapshot
Snapshot Generator
Creates Snapshot infrastructure for optimizing event sourcing aggregate rebuilds.
When to Use
| Scenario | Example |
|---|---|
| Long event streams | Aggregates with 100+ events in their history |
| Slow aggregate rebuild | Event replay taking too long for read operations |
| Frequent reads | Aggregates loaded many times per second |
| Large aggregates | Complex state requiring many events to reconstruct |
Component Characteristics
Snapshot
- Immutable state capture of an aggregate at a point in time
- Properties: aggregateId, aggregateType, version, state (JSON), createdAt
- Supports
fromArray()/toArray()for serialization - Version must be >= 1
SnapshotStoreInterface
save(Snapshot $snapshot): void— persist snapshot (upsert)load(string $aggregateId): ?Snapshot— retrieve latest snapshotdelete(string $aggregateId): void— remove all snapshots for aggregate
SnapshotStrategy
- Configurable event threshold (default: 100)
shouldTakeSnapshot(int $eventsSinceLastSnapshot): bool- Determines when a new snapshot should be captured
AggregateSnapshotter
- Application service coordinating snapshot operations
- Loads aggregate from snapshot + remaining events
- Takes snapshots when strategy threshold is met
Generation Process
Step 1: Generate Domain Components
Path: src/Domain/{BC}/Snapshot/
Snapshot.php— Immutable snapshot value objectSnapshotStoreInterface.php— Repository interface for snapshot persistence
Step 2: Generate Application Components
Path: src/Application/{BC}/Snapshot/
SnapshotStrategy.php— Configurable threshold strategyAggregateSnapshotter.php— Application service for snapshot operations
Step 3: Generate Infrastructure Components
Path: src/Infrastructure/{BC}/Snapshot/
DoctrineSnapshotStore.php— Doctrine DBAL implementation of SnapshotStoreInterface- Database migration SQL for snapshots table
Step 4: Generate Tests
SnapshotTest.php— Construction, serialization, validation testsSnapshotStrategyTest.php— Threshold behavior testsAggregateSnapshotterTest.php— Load and take snapshot tests
File Placement
| Component | Path |
|---|---|
| Snapshot, SnapshotStoreInterface | src/Domain/{BC}/Snapshot/ |
| SnapshotStrategy, AggregateSnapshotter | src/Application/{BC}/Snapshot/ |
| DoctrineSnapshotStore | src/Infrastructure/{BC}/Snapshot/ |
| Unit Tests | tests/Unit/Domain/{BC}/Snapshot/, tests/Unit/Application/{BC}/Snapshot/ |
Naming Conventions
| Component | Pattern | Example |
|---|---|---|
| Value Object | Snapshot |
Snapshot |
| Store Interface | SnapshotStoreInterface |
SnapshotStoreInterface |
| Strategy | SnapshotStrategy |
SnapshotStrategy |
| Application Service | AggregateSnapshotter |
AggregateSnapshotter |
| Infrastructure Store | DoctrineSnapshotStore |
DoctrineSnapshotStore |
| Test | {ClassName}Test |
SnapshotTest |
Quick Template Reference
Snapshot
final readonly class Snapshot
{
public function __construct(
public string $aggregateId,
public string $aggregateType,
public int $version,
public string $state,
public \DateTimeImmutable $createdAt
) {
// version >= 1 validation
}
public static function fromArray(array $data): self;
public function toArray(): array;
}
SnapshotStoreInterface
interface SnapshotStoreInterface
{
public function save(Snapshot $snapshot): void;
public function load(string $aggregateId): ?Snapshot;
public function delete(string $aggregateId): void;
}
SnapshotStrategy
final readonly class SnapshotStrategy
{
public function __construct(
private int $eventThreshold = 100
) {}
public function shouldTakeSnapshot(int $eventsSinceLastSnapshot): bool;
}
Usage Example
$snapshotter = new AggregateSnapshotter($snapshotStore, $strategy);
// Load aggregate from snapshot + remaining events
$result = $snapshotter->loadWithSnapshot($aggregateId, $eventStore);
$snapshot = $result['snapshot'];
$remainingEvents = $result['remainingEvents'];
$aggregate = $snapshot !== null
? Order::fromSnapshot($snapshot)
: new Order($aggregateId);
foreach ($remainingEvents as $event) {
$aggregate->apply($event);
}
// Take snapshot if threshold reached
$snapshotter->takeSnapshotIfNeeded(
aggregateId: $aggregateId,
aggregateType: 'Order',
version: $aggregate->getVersion(),
state: $aggregate->toSnapshot(),
eventsSinceSnapshot: count($remainingEvents)
);
Database Schema
CREATE TABLE snapshots (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
aggregate_id VARCHAR(36) NOT NULL,
aggregate_type VARCHAR(255) NOT NULL,
version INT UNSIGNED NOT NULL,
state JSON NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE INDEX idx_snapshots_aggregate_id (aggregate_id),
INDEX idx_snapshots_aggregate_type (aggregate_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Anti-patterns to Avoid
| Anti-pattern | Problem | Solution |
|---|---|---|
| Snapshot Every Event | Storage bloat, no performance gain | Use threshold strategy (e.g., every 100 events) |
| Mutable Snapshots | State corruption, debugging nightmares | Make Snapshot immutable (final readonly) |
| Missing Version | Cannot determine event replay start point | Always track version in snapshot |
| No Cleanup | Unbounded storage growth | Implement retention policy, keep only latest |
| Tight Coupling | Snapshot tied to infrastructure | Domain interface, infrastructure implementation |
| Skipping Validation | Invalid snapshots persisted | Validate version >= 1, non-empty state |
References
For complete PHP templates and examples, see:
references/templates.md— Snapshot, SnapshotStoreInterface, SnapshotStrategy, AggregateSnapshotter, DoctrineSnapshotStore templatesreferences/examples.md— OrderAggregate integration, event sourcing examples and tests
More from dykyi-roman/awesome-claude-code
psr-overview-knowledge
PHP Standards Recommendations (PSR) overview knowledge base. Provides comprehensive reference for all accepted PSRs including PSR-1,3,4,6,7,11,12,13,14,15,16,17,18,20. Use for PSR selection decisions and compliance audits.
22detect-code-smells
Detects code smells in PHP codebases. Identifies God Class, Feature Envy, Data Clumps, Long Parameter List, Long Method, Primitive Obsession, Message Chains, Inappropriate Intimacy. Generates actionable reports with refactoring recommendations.
15clean-arch-knowledge
Clean Architecture knowledge base. Provides patterns, antipatterns, and PHP-specific guidelines for Clean Architecture and Hexagonal Architecture audits.
15ddd-knowledge
DDD architecture knowledge base. Provides patterns, antipatterns, and PHP-specific guidelines for Domain-Driven Design audits.
14testing-knowledge
Testing knowledge base for PHP 8.4 projects. Provides testing pyramid, AAA pattern, naming conventions, isolation principles, DDD testing guidelines, and PHPUnit patterns.
12bug-root-cause-finder
Root cause analysis methods for PHP bugs. Provides 5 Whys technique, fault tree analysis, git bisect guidance, and stack trace parsing.
12