Awesome-claude-code create-snapshot
Generates Snapshot pattern for PHP 8.4. Creates aggregate snapshot infrastructure for event sourcing performance optimization with configurable strategies and version tracking. Includes unit tests.
install
source · Clone the upstream repo
git clone https://github.com/dykyi-roman/awesome-claude-code
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/dykyi-roman/awesome-claude-code "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/create-snapshot" ~/.claude/skills/dykyi-roman-awesome-claude-code-create-snapshot && rm -rf "$T"
manifest:
skills/create-snapshot/SKILL.mdsource content
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()
for serializationtoArray() - Version must be >= 1
SnapshotStoreInterface
— persist snapshot (upsert)save(Snapshot $snapshot): void
— retrieve latest snapshotload(string $aggregateId): ?Snapshot
— remove all snapshots for aggregatedelete(string $aggregateId): void
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/
— Immutable snapshot value objectSnapshot.php
— Repository interface for snapshot persistenceSnapshotStoreInterface.php
Step 2: Generate Application Components
Path:
src/Application/{BC}/Snapshot/
— Configurable threshold strategySnapshotStrategy.php
— Application service for snapshot operationsAggregateSnapshotter.php
Step 3: Generate Infrastructure Components
Path:
src/Infrastructure/{BC}/Snapshot/
— Doctrine DBAL implementation of SnapshotStoreInterfaceDoctrineSnapshotStore.php- Database migration SQL for snapshots table
Step 4: Generate Tests
— Construction, serialization, validation testsSnapshotTest.php
— Threshold behavior testsSnapshotStrategyTest.php
— Load and take snapshot testsAggregateSnapshotterTest.php
File Placement
| Component | Path |
|---|---|
| Snapshot, SnapshotStoreInterface | |
| SnapshotStrategy, AggregateSnapshotter | |
| DoctrineSnapshotStore | |
| Unit Tests | , |
Naming Conventions
| Component | Pattern | Example |
|---|---|---|
| Value Object | | |
| Store Interface | | |
| Strategy | | |
| Application Service | | |
| Infrastructure Store | | |
| Test | | |
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:
— Snapshot, SnapshotStoreInterface, SnapshotStrategy, AggregateSnapshotter, DoctrineSnapshotStore templatesreferences/templates.md
— OrderAggregate integration, event sourcing examples and testsreferences/examples.md