Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 15 additions & 18 deletions .claude/context.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
# Epoch Development Context

> **Automatically loaded in Claude Code sessions**
> This file provides essential context about the Epoch repository for LLM-assisted development.
> Start here for Epoch's development conventions and source map.

## Quick Reference

- **Repository**: Event Sourcing + CQRS Framework (Rust)
- **Version**: 1.0.0-alpha.18
- **Release candidate**: 0.1.0 (`epoch-journal` package, `epoch` library)
- **Core Pattern**: Decider Pattern (pure functional event sourcing)
- **Rust Edition**: 2021
- **Minimum Rust version**: 1.88

## Session Start Protocol

**At the start of each session, review**:

1. **[TODO.md](../TODO.md)** - Current work items and priorities
- Check "Current Sprint" section for active work
- Review "High Priority" for next tasks
- Note any blockers in "Known Issues"
1. **[TODO.md](../TODO.md)** - Archived 2025 planning notes, not the
current release backlog. Use the README and changelog for the
shipped API and version.

2. **[CHANGELOG.md](../CHANGELOG.md)** - Recent changes
- Review "Unreleased" section for latest updates
- Understand what changed since last session

3. **[Session Start Checklist](.claude/session-start.md)** - Detailed session setup
3. **[Session Start Checklist](session-start.md)** - Detailed session setup
- Verify development environment
- Review core principles
- Set session goals

**Throughout the session**:
- Update TODO.md when starting/completing work
- Add to CHANGELOG.md for user-facing changes
- Keep both files synchronized with work progress
**Throughout the session**: Update CHANGELOG.md for user-facing changes.

## Essential Reading

Expand Down Expand Up @@ -220,9 +217,8 @@ pub enum RepositoryVersion<V> {

## Known Issues & TODOs

1. **README Outdated**: References old `EventContext` API instead of Decider pattern
2. **Retry Logic**: Uses `thread::sleep` instead of `tokio::sleep` (alpha pragmatism)
3. **Missing Feature**: `LoadDecideAppendWithSnapshot` not yet implemented
1. **Retry Logic**: Uses `thread::sleep` instead of `tokio::sleep`
2. **Missing Feature**: `LoadDecideAppendWithSnapshot` not yet implemented

## File Locations

Expand All @@ -238,7 +234,8 @@ pub enum RepositoryVersion<V> {
│ │ ├── state.rs # State repository traits
│ │ ├── in_memory/ # In-memory backend
│ │ ├── esdb/ # EventStoreDB backend
│ │ └── redis/ # Redis backend
│ │ ├── redis/ # Redis backend
│ │ └── postgres/ # PostgreSQL backend
│ └── test_helpers/
│ ├── deciders.rs # Example UserDecider
│ └── repository.rs # Generic spec tests
Expand All @@ -259,10 +256,10 @@ Following guidelines from [claude-skills](https://github.com/Shearerbeard/claude

### Internal vs. External Documentation

- **Internal** (`docs/internal/`): Architecture decisions, coding patterns, LLM context
- **Internal** (`docs/internal/`): Design decisions and coding conventions for maintainers
- Target audience: Developers and LLM assistants
- Focus: WHY decisions were made, HOW patterns work
- Examples: Architecture docs, style guides, planning documents
- Examples: Architecture and style guides, plus implementation plans

- **External** (README, doc comments): User-facing API documentation
- Target audience: Library users
Expand All @@ -277,7 +274,7 @@ Files in `.claude/` and `docs/internal/` are designed to provide LLM assistants
- Common tasks and their implementations
- Known issues and limitations

This allows for consistent, context-aware assistance across sessions.
The source tree and README remain authoritative when these notes fall behind.

## Quick Start Commands

Expand Down
6 changes: 3 additions & 3 deletions .claude/session-start.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Session Start Checklist

> **Automatic Reference for Claude Code Sessions**
> This file provides a quick checklist and context for starting new development sessions.
> Archived 2025 checklist. Use the root README for current setup,
> feature, and test commands. `TODO.md` is also a historical snapshot.

**Date**: {SESSION_DATE}

Expand Down Expand Up @@ -99,7 +99,7 @@ cargo fmt --check
### Success Criteria

By end of session:
- [ ] All tests passing
- [ ] Run the feature-specific suite documented in the README
- [ ] Code formatted and linted
- [ ] TODO.md updated
- [ ] CHANGELOG.md updated (if applicable)
Expand Down
28 changes: 28 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copy this file to .env before running the integration tests:
#
# cp .env.example .env
# docker compose up -d
# cargo test
#
# The backends read these at test time via dotenv, and the suite panics
# with "File .env or Env Vars not found" when the file is missing.

# EventStoreDB. Matches the eventstore.db service in docker-compose.yml.
# Used by the esdb feature, which is on by default.
ESDB_CONNECTION_STRING=esdb://admin:changeit@localhost:2113?tls=false

# Redis with the RedisJSON module. Matches the redis service in
# docker-compose.yml. Used by the redis feature, which is on by default.
REDIS_CONNECTION_STRING=redis://localhost:6379

# Postgres. Matches the postgres service in docker-compose.yml, which
# publishes on 54321 to stay clear of any system postgres on 5432.
#
# The postgres feature is NOT in the default set, so its tests only run
# when you ask for them:
#
# cargo test --features postgres
#
# Required: the postgres tests refuse to run without it rather than
# guessing a database, since they migrate schema into whatever they hit.
EPOCH_PG_TEST_URL=postgres://epoch:epoch@localhost:54321/epoch
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI

on:
push:
pull_request:

jobs:
rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install supported Rust toolchain
run: rustup toolchain install 1.88.0 --profile minimal --component clippy,rustfmt
- name: Format
run: cargo +1.88.0 fmt --check
- name: Lint all targets and features
run: cargo +1.88.0 clippy --all-targets --all-features -- -D warnings
- name: Test without backends
run: cargo +1.88.0 test --no-default-features
- name: Check README doctest and example
run: cargo +1.88.0 test --doc && cargo +1.88.0 run --no-default-features --example counter

backends:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install supported Rust toolchain
run: rustup toolchain install 1.88.0 --profile minimal
- name: Start test services
run: |
cp .env.example .env
docker compose up -d
for attempt in $(seq 1 60); do
if ( </dev/tcp/127.0.0.1/2113 ) 2>/dev/null &&
( </dev/tcp/127.0.0.1/6379 ) 2>/dev/null &&
( </dev/tcp/127.0.0.1/54321 ) 2>/dev/null; then
exit 0
fi
sleep 2
done
docker compose ps
exit 1
- name: Test default backends
run: cargo +1.88.0 test
- name: Test every backend
run: cargo +1.88.0 test --all-features
- name: Stop test services
if: always()
run: docker compose down
15 changes: 15 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Epoch contributor context

Start with [README.md](README.md). It owns the install, example,
feature, build, and test instructions. [CHANGELOG.md](CHANGELOG.md)
records changes. The `TODO.md` file is an archived 2025 snapshot, not
the current release plan.

`src/decider.rs` defines the domain interfaces. Persistence interfaces
and backends live in `src/repository/`; `src/strategies/` combines
deciders with repositories. The public counter example is in
`examples/counter.rs` and appears verbatim in the README.

Treat the README's Rust block as executable: it is included in crate
docs and runs under `cargo test --doc`. Run the relevant feature tests
and the checks named in the README when changing behavior or docs.
42 changes: 31 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
# Changelog

<!-- vale ai-tells.OverusedVocabulary = NO -->
<!-- vale-reason: Keep a Changelog's standard wording, not generated prose. -->
All notable changes to this project will be documented in this file.
<!-- vale ai-tells.OverusedVocabulary = YES -->

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Comprehensive internal documentation structure
- A compiled counter example that exercises the current Decider and
Evolver traits without a backend.
- An accessor for the events in `CommandResponse`.
- Pull-request checks for the supported Rust floor and service-backed
repository tests.
- PostgreSQL repository backend behind the opt-in `postgres` feature.
- Internal documentation structure
- Architecture and philosophy documentation (docs/internal/planning/epoch-architecture-philosophy.md)
- Coding style guide with Railway-Oriented Programming patterns (docs/internal/planning/coding-style-guide.md)
- Documentation guidelines for internal vs external docs (docs/internal/documentation-guidelines.md)
Expand All @@ -30,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- LLM-assisted development patterns
- Templates for TODO items and CHANGELOG entries
- PostgreSQL repository implementation planning document (docs/internal/planning/postgres-repository-implementation.md)
- Comprehensive 4-phase implementation plan (8-12 hours total)
- 4-phase implementation plan (8-12 hours total)
- Database schema design with JSONB event storage
- Trait implementation patterns following ESDB and Redis
- Connection pooling strategy with bb8
Expand All @@ -41,6 +50,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Performance considerations and indexing strategy

### Changed
- Declare Rust 1.88 as the minimum supported version after checking
an unlocked dependency resolution with every feature enabled.
- Prepare the first public package as `epoch-journal` while retaining
`epoch` as the library import. Git consumers must update their
dependency declaration to name the new package.
- Update the EventStoreDB client to 4.0 and replace the test-only
`dotenv` dependency with `dotenvy`.
- Take event slices in repository append methods instead of requiring
`Vec` references.
- Enhanced coding style guide with trucker_buddy_rs patterns
- Added Railway-Oriented Programming section with visual diagrams
- Added "Making Illegal States Unrepresentable" principle
Expand All @@ -64,12 +82,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- None

### Fixed
- None
- Replace the removed EventContext README example with a runnable
Decider example.
- Use one consistent ordering implementation for Redis stream versions.

### Security
- None

## [1.0.0-alpha.18] - Prior to Documentation
## Repository history (unpublished)

The old `1.0.0-alpha.18` version was used in the repository, not
published to crates.io. The notes below describe that code line.

### Added
- Decider pattern traits (Evolver, Decider, DeciderWithContext)
Expand Down Expand Up @@ -101,9 +124,9 @@ This project uses [Semantic Versioning](https://semver.org/):
- **MAJOR** version: Incompatible API changes
- **MINOR** version: Add functionality in a backwards compatible manner
- **PATCH** version: Backwards compatible bug fixes
- **Alpha/Beta** suffix: Pre-release versions (current: alpha)
- **Alpha/Beta** suffix: Pre-release versions

### Alpha Status (1.0.0-alpha.x)
### Earlier alpha status (1.0.0-alpha.x)

During alpha:
- API may change without notice
Expand All @@ -116,8 +139,8 @@ During alpha:
To move from alpha to 1.0.0 stable:
- [ ] API is stable and documented
- [ ] README examples use current Decider pattern
- [ ] All three backends (in-memory, ESDB, Redis) fully tested
- [ ] Comprehensive documentation complete
- [ ] All four backends (in-memory, ESDB, Redis, PostgreSQL) fully tested
- [ ] Public traits and backend limits documented
- [ ] LoadDecideAppendWithSnapshot implemented
- [ ] Migration guide from alpha to 1.0
- [ ] Performance benchmarks established
Expand Down Expand Up @@ -193,6 +216,3 @@ To move from alpha to 1.0.0 stable:
- [Conventional Commits](https://www.conventionalcommits.org/)

---

[Unreleased]: https://github.com/Shearerbeard/Epoch/compare/v1.0.0-alpha.18...HEAD
[1.0.0-alpha.18]: https://github.com/Shearerbeard/Epoch/releases/tag/v1.0.0-alpha.18
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
20 changes: 15 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
[package]
name = "epoch"
version = "1.0.0-alpha.18"
name = "epoch-journal"
version = "0.1.0"
edition = "2021"
rust-version = "1.88"
description = "Event sourcing with deciders and pluggable event repositories"
license = "Apache-2.0"
repository = "https://github.com/Shearerbeard/Epoch"
readme = "README.md"
keywords = ["event-sourcing", "cqrs", "event-store", "decider"]
categories = ["database-implementations", "asynchronous"]
exclude = ["/.claude/", "/.github/", "/AGENTS.md", "/CLAUDE.md", "/TODO.md", "/deny.toml", "/docs/internal/", "/docs/design/", "/docs/research/", "/docs/README.md"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "epoch"

[features]
default = ["in_memory", "esdb", "redis"]
Expand All @@ -14,7 +23,7 @@ postgres = ["dep:tokio-postgres", "dep:bb8", "dep:bb8-postgres", "dep:serde_json

[dependencies]
async-trait = "0.1.53"
eventstore = { version = "2.2.0", optional = true }
eventstore = { version = "4.0.0", optional = true }
redis-om = { version = "0.1.0", features = ["json"], optional = true}
rusty_ulid = "2.0.0"
serde = { version = "1.0.136", features = ["derive"] }
Expand All @@ -30,5 +39,6 @@ actix-rt = "2.7.0"
assert_matches = "1.5.0"
const-random = "0.1.15"
autoincrement = "1"
dotenv = "0.15.0"
dotenvy = "0.15"
futures = "0.3.25"
tokio = { version = "1", features = ["time"] }
Loading
Loading