Document that EventStore interface has no Update/Delete methods, enforcing
append-only semantics by design. Events are immutable once persisted.
Changes:
- Update EventStore interface documentation in event.go to explicitly state
immutability guarantee and explain why Update/Delete methods are absent
- Add detailed retention policy documentation to JetStreamConfig showing
how MaxAge limits enforce automatic expiration without manual deletion
- Document JetStreamEventStore's immutability guarantee with storage-level
explanation of file-based storage and limits-based retention
- Add comprehensive immutability tests verifying:
- Events cannot be modified after persistence
- No Update or Delete methods exist on EventStore interface
- Versions are monotonically increasing
- Events cannot be deleted through the API
- Update README with detailed immutability section explaining:
- Interface-level append-only guarantee
- Storage-level immutability through JetStream configuration
- Audit trail reliability
- Pattern for handling corrections (append new event)
Closes#60
Co-Authored-By: Claude Code <noreply@anthropic.com>
Add EventStored internal event published to the EventBus when events are
successfully persisted. This allows observability components (metrics,
projections, audit systems) to react to persisted events without coupling
to application code.
Implementation:
- Add EventTypeEventStored constant to define the event type
- Update InMemoryEventStore with optional EventBroadcaster support
- Add NewInMemoryEventStoreWithBroadcaster constructor
- Update JetStreamEventStore with EventBroadcaster support
- Add NewJetStreamEventStoreWithBroadcaster constructor
- Implement publishEventStored() helper method
- Publish EventStored containing EventID, ActorID, Version, Timestamp
- Only publish on successful SaveEvent (not on version conflicts)
- Automatically recorded in metrics through normal Publish flow
Test coverage:
- EventStored published after successful SaveEvent
- No EventStored published on version conflict
- Multiple EventStored events published in order
- SaveEvent works correctly without broadcaster (nil-safe)
Closes#61
Co-Authored-By: Claude Code <noreply@anthropic.com>
Add ReplayError and ReplayResult types to capture information about
malformed events encountered during replay. This allows callers to
inspect and handle corrupted data rather than having it silently skipped.
Key changes:
- Add ReplayError type with sequence number, raw data, and underlying error
- Add ReplayResult type containing both successfully parsed events and errors
- Add EventStoreWithErrors interface for stores that can report replay errors
- Implement GetEventsWithErrors on JetStreamEventStore
- Update GetEvents to maintain backward compatibility (still skips malformed)
- Add comprehensive unit tests for the new types
This addresses the issue of silent data loss during event-sourced replay
by giving callers visibility into data quality issues.
Closes#39
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Metadata field (map[string]string) to Event struct with omitempty
- Add helper methods for common metadata: SetCorrelationID/GetCorrelationID,
SetCausationID/GetCausationID, SetUserID/GetUserID, SetTraceID/GetTraceID,
SetSpanID/GetSpanID
- Add WithMetadataFrom helper for copying metadata between events
- Add metadata key constants for standard fields
- Add comprehensive unit tests for metadata serialization and helpers
- Add store tests verifying metadata persistence
Closes#7
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ErrVersionConflict error type and VersionConflictError for detailed
conflict information
- Implement version validation in InMemoryEventStore.SaveEvent that rejects
events with version <= current latest version
- Implement version validation in JetStreamEventStore.SaveEvent with version
caching for performance
- Add comprehensive tests for version conflict detection including concurrent
writes to same actor
- Document versioning semantics in EventStore interface and CLAUDE.md
This ensures events have monotonically increasing versions per actor and
provides clear error messages for version conflicts, enabling optimistic
concurrency control patterns.
Closes#6
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>