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.
Works with
---
name: create-snapshot
description: 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.
license: MIT
---
# 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 snapshot
- `delete(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/`
1. `Snapshot.php` — Immutable snapshot value object
2. `SnapshotStoreInterface.php` — Repository interface for snapshot persistence
### Step 2: Generate Application Components
**Path:** `src/Application/{BC}/Snapshot/`
1. `SnapshotStrategy.php` — Configurable threshold strategy
2. `AggregateSnapshotter.php` — Application service for snapshot operations
### Step 3: Generate Infrastructure Components
**Path:** `src/Infrastructure/{BC}/Snapshot/`
1. `DoctrineSnapshotStore.php` — Doctrine DBAL implementation of SnapshotStoreInterface
2. Database migration SQL for snapshots table
### Step 4: Generate Tests
1. `SnapshotTest.php` — Construction, serialization, validation tests
2. `SnapshotStrategyTest.php` — Threshold behavior tests
3. `AggregateSnapshotterTest.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
```php
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
```php
interface SnapshotStoreInterface
{
public function save(Snapshot $snapshot): void;
public function load(string $aggregateId): ?Snapshot;
public function delete(string $aggregateId): void;
}
```
### SnapshotStrategy
```php
final readonly class SnapshotStrategy
{
public function __construct(
private int $eventThreshold = 100
) {}
public function shouldTakeSnapshot(int $eventsSinceLastSnapshot): bool;
}
```
---
## Usage Example
```php
$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
```sql
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 templates
- `references/examples.md` — OrderAggregate integration, event sourcing examples and testsMore Testing skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
setup-pre-commit
mattpocock/skills
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
agent-browser
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

