Files
aether/CLAUDE.md
Hugo Nijhuis f7b7335ef5
All checks were successful
CI / build (push) Successful in 1m25s
Fix manifesto links
- Update manifesto links to use absolute Gitea URLs

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-08 19:39:16 +01:00

3.0 KiB

Aether

Distributed actor system with event sourcing for Go, powered by NATS.

Organization Context

This repo is part of Flowmade. See:

Setup

git clone git@git.flowmade.one:flowmade-one/aether.git
cd aether
go mod download

Requires NATS server for integration tests:

# Install NATS
brew install nats-server

# Run with JetStream enabled
nats-server -js

Project Structure

aether/
├── event.go           # Event, ActorSnapshot, EventStore interface
├── eventbus.go        # EventBus, EventBroadcaster interface
├── nats_eventbus.go   # NATSEventBus - cross-node event broadcasting
├── store/
│   ├── memory.go      # InMemoryEventStore (testing)
│   └── jetstream.go   # JetStreamEventStore (production)
├── cluster/
│   ├── manager.go     # ClusterManager
│   ├── discovery.go   # NodeDiscovery
│   ├── hashring.go    # ConsistentHashRing
│   ├── shard.go       # ShardManager
│   ├── leader.go      # LeaderElection
│   └── types.go       # Cluster types
└── model/
    └── model.go       # EventStorming model types

Development

make build    # Build the library
make test     # Run tests
make lint     # Run linters

Architecture

Event Sourcing

Events are the source of truth. State is derived by replaying events.

// Create an event
event := &aether.Event{
    ID:        uuid.New().String(),
    EventType: "OrderPlaced",
    ActorID:   "order-123",
    Version:   1,
    Data:      map[string]interface{}{"total": 100.00},
    Timestamp: time.Now(),
}

// Persist to event store
store.SaveEvent(event)

// Replay events to rebuild state
events, _ := store.GetEvents("order-123", 0)

Namespace Isolation

Namespaces provide logical boundaries for events and subscriptions:

// Subscribe to events in a namespace
ch := eventBus.Subscribe("tenant-abc")

// Events are isolated per namespace
eventBus.Publish("tenant-abc", event)  // Only tenant-abc subscribers see this

Clustering

Aether handles node discovery, leader election, and shard distribution:

// Create cluster manager
manager := cluster.NewClusterManager(natsConn, nodeID)

// Join cluster
manager.Start()

// Leader election happens automatically
if manager.IsLeader() {
    // Coordinate shard assignments
}

Key Patterns

  • Events are immutable - Never modify, only append
  • Snapshots for performance - Periodically snapshot state to avoid full replay
  • Namespaces for isolation - Not multi-tenancy, just logical boundaries
  • NATS for everything - Events, pub/sub, clustering all use NATS