### Publish Example Code Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/PUBLISHING.md Compile and run specific examples from the eventcore-examples package. ```bash # Publish example code cargo run --package eventcore-examples --example banking cargo run --package eventcore-examples --example ecommerce ``` -------------------------------- ### Start Development Environment Source: https://github.com/jwilger/eventcore/blob/main/AGENTS.md Enter the Nix development shell for pinned toolchains. Start Postgres separately if needed. ```bash nix develop ``` -------------------------------- ### Compile Project Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/02-getting-started/01-setup.md Use this command to compile your project and verify the setup. Ensure all dependencies are correctly installed. ```bash cargo build ``` -------------------------------- ### End-to-End Example Execution Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/PUBLISHING.md Runs end-to-end example applications for banking and e-commerce scenarios. ```bash # End-to-end scenarios cargo run --package eventcore-examples --bin banking cargo run --package eventcore-examples --bin ecommerce ``` -------------------------------- ### Example Release Timeline Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/VERSIONING.md Illustrates a typical timeline from alpha versions to a stable release. ```text 1.0.0-alpha.1 -> API design and early implementation 1.0.0-alpha.2 -> Core features complete 1.0.0-beta.1 -> Feature complete, API stabilization 1.0.0-beta.2 -> Bug fixes and polish 1.0.0-rc.1 -> Final testing 1.0.0 -> Stable release ``` -------------------------------- ### SQL Migration File Example Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/07-operations/01-deployment-strategies.md An example SQL migration file for an application read model. This demonstrates creating a table and indexes for query-side state, separate from EventCore's internal schema. ```sql -- migrations/001_account_summary_read_model.sql -- A query-side read model maintained by a projection. EventCore's own event -- store schema (eventcore_events) is created separately by migrate(). CREATE TABLE account_summary ( account_id UUID PRIMARY KEY, balance_cents BIGINT NOT NULL DEFAULT 0, last_activity_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); -- Indexes for the application's query patterns over this read model. CREATE INDEX idx_account_summary_last_activity ON account_summary (last_activity_at); CREATE INDEX idx_account_summary_updated_at ON account_summary (updated_at); ``` -------------------------------- ### Start PostgreSQL with Docker Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/02-getting-started/01-setup.md Use this command to start a PostgreSQL instance using Docker for EventCore. Ensure the environment variables for password and database name are set correctly. ```bash docker run -d \ --name eventcore-postgres \ -e POSTGRES_PASSWORD=password \ -e POSTGRES_DB=taskmaster \ -p 5432:5432 \ postgres:17 ``` -------------------------------- ### Manual Publishing Process - Initial Steps Source: https://github.com/jwilger/eventcore/blob/main/docs/RELEASE_PROCESS.md Commands to ensure the local repository is up-to-date before starting the manual publishing process. ```bash git checkout main git pull origin main ``` -------------------------------- ### Stream Versioning Examples Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/03-core-concepts/02-events-and-stores.md Illustrates how StreamVersion works, starting from 0 for an empty stream and incrementing with each appended event. Used for optimistic concurrency control. ```rust // Versions start at 0 (empty stream) and increment as events are appended. let empty = StreamVersion::new(0); let after_one_event = empty.increment(); // StreamVersion::new(1) ``` -------------------------------- ### EventCore Structured Logging Example Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/01-introduction/04-architecture.md Provides an example of structured logging output from EventCore, including command details, execution duration, and events written. ```json {"level":"info", "command":"TransferMoney", "duration_ms":15, "events_written":2} ``` -------------------------------- ### Stream Partitioning Example Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/03-core-concepts/04-multi-stream-atomicity.md Demonstrates partitioning a stream by customer segment to manage load. This is useful when a single stream becomes a bottleneck. ```rust // Instead of one hot stream let stream = StreamId::try_new("orders").unwrap(); // Partition by customer segment let stream = StreamId::try_new(format!("orders-{}", customer_id.hash() % 16 )).unwrap(); ``` -------------------------------- ### SqliteEventStore Construction Examples Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/08-reference/02-configuration-reference.md Shows how to create a SqliteEventStore for a file-backed database with optional encryption, and an in-memory store for testing purposes. Both require migrating the schema. ```rust use eventcore_sqlite::{SqliteConfig, SqliteEventStore}; use std::path::PathBuf; // File-backed store. let config = SqliteConfig { path: PathBuf::from("./events.db"), encryption_key: None, }; let store = SqliteEventStore::new(config)?; store.migrate().await?; // In-memory store (for testing). let store = SqliteEventStore::in_memory()?; store.migrate().await?; ``` -------------------------------- ### Clone EventCore Repository Source: https://github.com/jwilger/eventcore/blob/main/CONTRIBUTING.md Clone your forked repository to start development. ```bash git clone https://github.com/YOUR_USERNAME/eventcore.git ``` -------------------------------- ### Define Command with Versioning Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/03-core-concepts/01-commands-and-macros.md Demonstrates how to version commands to handle API evolution. This example shows `TransferMoneyV2` with an added `category` field. ```rust #[derive(Command, Clone)] #[command(version = 2)] struct TransferMoneyV2 { #[stream] from_account: StreamId, #[stream] to_account: StreamId, amount: Money, reference: String, // New in V2 category: TransferCategory, } ``` -------------------------------- ### Release Process: CHANGELOG Entry Example Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/PUBLISHING.md Format changelog entries according to semantic versioning, detailing additions, changes, and fixes. ```markdown ## [1.0.0] - 2024-01-15 ### Added - New feature descriptions ### Changed - Breaking change descriptions ### Fixed - Bug fix descriptions ``` -------------------------------- ### EventFilter Examples Source: https://github.com/jwilger/eventcore/blob/main/blueprints/projection-system.md Demonstrates how to construct EventFilter predicates to select specific events for projection. Filters are pushed down to the backend for efficiency. ```rust EventFilter::all() EventFilter::prefix(StreamPrefix::new("user/", '/')) EventFilter::pattern(StreamPattern::new("*?user/*")) .with_event_type("UserRegistered") ``` -------------------------------- ### Manual PostgreSQL Restore from Dump Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/07-operations/03-backup-recovery.md Restore an EventCore database from a `pg_dump` custom-format backup file using `pg_restore`. This example assumes a fresh database has been created. ```bash # Restore into a fresh database createdb eventcore_restored pg_restore \ --dbname="postgresql://.../eventcore_restored" \ --no-owner \ eventcore-20260101T020000.dump ``` -------------------------------- ### Start PostgreSQL Database Source: https://github.com/jwilger/eventcore/blob/main/README.md Starts the PostgreSQL database in detached mode using Docker Compose. Ensure Docker is installed and running. ```bash docker-compose up -d # Start PostgreSQL ``` -------------------------------- ### Build and Serve Interactive Tutorials with mdbook Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/PUBLISHING.md Use mdbook to build static tutorial sites and serve them locally for preview. ```bash # Publish interactive tutorials mdbook build docs/tutorial mdbook serve --open ``` -------------------------------- ### PostgresEventStore Construction Examples Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/08-reference/02-configuration-reference.md Demonstrates how to construct a PostgresEventStore using default configuration, custom configuration via PostgresConfig, and applying schema migrations. Also shows how to verify connectivity. ```rust use std::num::NonZeroU32; use std::time::Duration; use eventcore_postgres::{MaxConnections, PostgresConfig, PostgresEventStore}; // Default configuration (10 connections, 30s acquire, 10m idle). let store = PostgresEventStore::new("postgresql://localhost/eventcore").await?; // Custom configuration via PostgresConfig. let config = PostgresConfig { max_connections: MaxConnections::new( NonZeroU32::new(20).expect("20 is non-zero"), ), acquire_timeout: Duration::from_secs(10), idle_timeout: Duration::from_secs(300), }; let store = PostgresEventStore::with_config("postgresql://localhost/eventcore", config).await?; // Apply the bundled schema migrations. store.migrate().await; // Optionally verify connectivity (panics if the database is unreachable). store.ping().await; ``` -------------------------------- ### EventStoreError Example Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/08-reference/03-error-reference.md Provides an example of an `CommandError::EventStoreError`, detailing a version conflict during an event store operation. ```text Error: event store error: version conflict on stream account-123: expected version 4, found 5 ``` -------------------------------- ### StreamId and StreamPrefix Validation Examples Source: https://github.com/jwilger/eventcore/blob/main/docs/adr/ADR-017-streamid-reserved-characters.md Examples of valid and invalid identifier construction based on the reserved character constraints. ```rust StreamId::try_new("account-*") ``` ```rust StreamPrefix::try_new("account-") ``` ```rust StreamPrefix::try_new("account-*") ``` -------------------------------- ### Pre-Release: Performance and Documentation Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/PUBLISHING.md Validate performance with benchmarks and generate documentation for the workspace. ```bash # Performance validation cargo bench # Documentation generation cargo doc --workspace --no-deps ``` -------------------------------- ### Conventional Commit Message Examples Source: https://github.com/jwilger/eventcore/blob/main/CONTRIBUTING.md Examples of valid commit messages following the Conventional Commits format for different types and scopes. ```text feat(core): add retry policy configuration to execute() ``` ```text fix(postgres): prevent advisory lock leak on transaction rollback ``` ```text refactor(types): extract StreamVersion validation into nutype ``` ```text test(sqlite): add contract tests for SQLCipher encryption mode ``` ```text chore: update workspace dependencies to latest compatible versions ``` -------------------------------- ### Start PostgreSQL Service Source: https://github.com/jwilger/eventcore/blob/main/CONTRIBUTING.md Start the PostgreSQL service in detached mode using Docker Compose. This is only required for running PostgreSQL backend tests. ```bash docker-compose up -d ``` -------------------------------- ### Enter Development Environment Source: https://github.com/jwilger/eventcore/blob/main/README.md Use this command to enter the Nix development environment for the project. This sets up all necessary tools and dependencies. ```bash # Setup nix develop # Enter dev environment ``` -------------------------------- ### Example Configuration API Usage Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/design/observability-integration-design.md Demonstrates how to configure and register OpenTelemetry and Prometheus exporters with an EventStore. This shows the builder pattern for OpenTelemetry and direct instantiation for Prometheus. ```rust // Example usage let mut event_store = PostgresEventStore::new(config).await?; // Enable OpenTelemetry let otel_exporter = OpenTelemetryExporter::builder() .with_endpoint("http://localhost:4317") .with_service_name("my-service") .build()?; event_store.register_exporter(Box::new(otel_exporter)); // Enable Prometheus let prometheus_exporter = PrometheusExporter::new(); let metrics_endpoint = prometheus_exporter.create_http_endpoint(9090); event_store.register_exporter(Box::new(prometheus_exporter)); ``` -------------------------------- ### Navigate to Project Root Source: https://github.com/jwilger/eventcore/blob/main/docs/development-archive/BENCHMARKS.md Before running benchmarks, navigate to the project's root directory. ```bash # Navigate to project root cd /home/jwilger/projects/eventcore ``` -------------------------------- ### Run projection using a builder pattern Source: https://github.com/jwilger/eventcore/blob/main/docs/adr/ADR-029-projection-runner-api-simplification.md Example of a verbose builder pattern that is considered unnecessary when all backends are the same. ```rust ProjectionRunner::new(projector, &store) .with_checkpoint_store(&store) .with_coordinator(&store) .run() ``` -------------------------------- ### Run projection with multiple backend parameters Source: https://github.com/jwilger/eventcore/blob/main/docs/adr/ADR-029-projection-runner-api-simplification.md Example of a verbose and discouraged approach where each backend is passed individually. ```rust run_projection(projector, &store, &store, &store).await?; ``` -------------------------------- ### Run EventCore Demo Source: https://github.com/jwilger/eventcore/blob/main/eventcore-demo/README.md Executes the EventCore demo application. Defaults to a local PostgreSQL instance. ```bash cargo run -p eventcore-demo ``` -------------------------------- ### BusinessRuleViolation Error Example Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/08-reference/03-error-reference.md Illustrates the display format for a `CommandError::BusinessRuleViolation` when a business rule is broken, such as insufficient funds. ```text Error: insufficient funds for account account-123: balance=50, attempted_withdrawal=100 ``` -------------------------------- ### Multiple Stream Declarations Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/03-core-concepts/01-commands-and-macros.md Example of a command struct declaring multiple distinct streams using the #[stream] attribute. ```rust #[derive(Command, Clone)] struct ProcessOrder { #[stream] order_id: StreamId, #[stream] customer_id: StreamId, #[stream] inventory_id: StreamId, #[stream] payment_id: StreamId, } ``` -------------------------------- ### Basic Stream Declaration with #[stream] Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/03-core-concepts/01-commands-and-macros.md Example of a command struct declaring a single stream using the #[stream] attribute. ```rust #[derive(Command, Clone)] struct UpdateProfile { #[stream] user_id: StreamId, // Single stream } ``` -------------------------------- ### Command Execution Flow Source: https://github.com/jwilger/eventcore/blob/main/blueprints/command-execution.md Illustrates the step-by-step process of command execution, including reading streams, state reconstruction, dynamic discovery, event handling, and atomic persistence with retries. ```text execute(store, command, policy) │ ├── Loop (attempt 0..max_retries): │ ├── Read all declared streams │ ├── Reconstruct state via apply() fold │ ├── Optional: dynamic stream discovery via stream_resolver() │ ├── Call handle(state) → NewEvents or CommandError │ ├── Build StreamWrites with expected versions │ ├── append_events() → success or VersionConflict │ │ │ ├── On success: return ExecutionResponse(attempts) │ ├── On VersionConflict + retries left: backoff, continue │ └── On permanent error: return Err immediately │ └── Max retries exhausted: return ConcurrencyError ``` -------------------------------- ### Configure and Initialize SQLite Event Store Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/02-getting-started/01-setup.md Set up a file-backed SQLite database for persistent storage. The `SqliteEventStore::new` function is synchronous and requires a `SqliteConfig`. No external database server is needed. ```rust use eventcore_sqlite::{SqliteConfig, SqliteEventStore}; use std::path::PathBuf; // File-backed store - data persists across restarts. // `SqliteEventStore::new` is synchronous and takes a `SqliteConfig`. let config = SqliteConfig { path: PathBuf::from("./taskmaster.db"), encryption_key: None, // Some(key) enables SQLCipher encryption }; let store = SqliteEventStore::new(config)?; ``` -------------------------------- ### Naive EventStore Implementation Source: https://github.com/jwilger/eventcore/blob/main/docs/adr/ADR-013-eventstore-contract-testing.md An example of an incorrect implementation that fails to perform version checking, violating the EventStore contract. ```rust async fn append_events(&self, writes: StreamWrites) -> Result { // Naive implementation - just writes events without checking versions! // This compiles but violates the contract. Ok(EventStreamSlice { /* ... */ }) } ``` -------------------------------- ### Version Lockstep Enforcement Example Source: https://github.com/jwilger/eventcore/blob/main/docs/RELEASE_PROCESS.md Demonstrates how a single workspace version is maintained across all crates, ensuring compatibility. ```toml [workspace.package] version = "0.8.0" [workspace.dependencies] eventcore-types = { workspace = true } eventcore-macros = { workspace = true } eventcore = { workspace = true } eventcore-testing = { workspace = true } eventcore-memory = { workspace = true } eventcore-postgres = { workspace = true } eventcore-sqlite = { workspace = true } eventcore-fs = { workspace = true } eventcore-examples = { workspace = true } ``` -------------------------------- ### ConcurrencyError Example Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/08-reference/03-error-reference.md Shows the error message format for `CommandError::ConcurrencyError`, indicating that optimistic concurrency conflicts persisted after all retries. ```text Error: concurrency conflict after 3 retry attempts ``` -------------------------------- ### Manual Publishing Process - Step 3: Create Git Tags Source: https://github.com/jwilger/eventcore/blob/main/docs/RELEASE_PROCESS.md Commands to create git tags for each released crate. Replace '0.X.Y' with the actual version number. ```bash git tag -a eventcore-v0.X.Y -m "Release eventcore v0.X.Y" git tag -a eventcore-types-v0.X.Y -m "Release eventcore-types v0.X.Y" git tag -a eventcore-macros-v0.X.Y -m "Release eventcore-macros v0.X.Y" git tag -a eventcore-testing-v0.X.Y -m "Release eventcore-testing v0.X.Y" git tag -a eventcore-memory-v0.X.Y -m "Release eventcore-memory v0.X.Y" git tag -a eventcore-postgres-v0.X.Y -m "Release eventcore-postgres v0.X.Y" git tag -a eventcore-sqlite-v0.X.Y -m "Release eventcore-sqlite v0.X.Y" git tag -a eventcore-fs-v0.X.Y -m "Release eventcore-fs v0.X.Y" git tag -a eventcore-examples-v0.X.Y -m "Release eventcore-examples v0.X.Y" ``` -------------------------------- ### Complete Money Transfer Command Logic Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/01-introduction/01-what-is-eventcore.md This example demonstrates how to define a `TransferMoney` command using EventCore. It includes state reconstruction, business logic validation for sufficient funds, and the atomic creation of withdrawal and deposit events. ```rust use eventcore::{Command, CommandError, CommandLogic, NewEvents, StreamId}; #[derive(Command)] struct TransferMoney { #[stream] from_account: StreamId, #[stream] to_account: StreamId, amount: Money, } impl CommandLogic for TransferMoney { type State = AccountBalances; type Event = BankingEvent; fn apply(&self, state: Self::State, event: &Self::Event) -> Self::State { // Update state based on events (pure function: owned state in, owned state out) match event { BankingEvent::MoneyWithdrawn { account_id, amount, .. } => { state.debit(account_id, *amount) } BankingEvent::MoneyDeposited { account_id, amount, .. } => { state.credit(account_id, *amount) } } } fn handle(&self, state: Self::State) -> Result, CommandError> { // Check balance let from_balance = state.balance(&self.from_account); if from_balance < self.amount.value() { return Err(format!( "Insufficient funds: balance={}, requested={}", from_balance, self.amount ) .into()); } // Create atomic events for both accounts (domain events) let withdraw = BankingEvent::MoneyWithdrawn { account_id: self.from_account.clone(), amount: self.amount, }; let deposit = BankingEvent::MoneyDeposited { account_id: self.to_account.clone(), amount: self.amount, }; Ok(vec![withdraw, deposit].into()) } } ``` -------------------------------- ### Event Granularity Examples Source: https://github.com/jwilger/eventcore/blob/main/docs/manual/03-core-concepts/02-events-and-stores.md Illustrates choosing the right level of detail for events, avoiding overly coarse or fine-grained structures. ```rust // ❌ Too coarse - loses important details struct OrderUpdated { order_id: OrderId, new_state: OrderState, // What actually changed? } // ❌ Too fine - creates event spam struct OrderFieldUpdated { order_id: OrderId, field_name: String, old_value: Value, new_value: Value, } // ✅ Just right - meaningful business events enum OrderEvent { OrderPlaced { customer: CustomerId, items: Vec }, PaymentReceived { amount: Money, method: PaymentMethod }, OrderShipped { tracking: TrackingNumber }, OrderDelivered { signed_by: String }, } ``` -------------------------------- ### Simple Case Usage of run_projection Source: https://github.com/jwilger/eventcore/blob/main/docs/adr/ADR-029-projection-runner-api-simplification.md Example of using the `run_projection` function in a common scenario where PostgreSQL provides all necessary traits. ```rust // PostgreSQL provides all three traits run_projection(my_projector, &postgres_store).await?; ```