# Aether Distributed actor system with event sourcing for Go, powered by NATS. ## Organization Context This repo is part of Flowmade. See: - [Organization manifesto](https://git.flowmade.one/flowmade-one/architecture/src/branch/main/manifesto.md) - who we are, what we believe - [Repository map](https://git.flowmade.one/flowmade-one/architecture/src/branch/main/repos.md) - how this fits in the bigger picture - [Vision](./vision.md) - what this specific product does ## Setup ```bash git clone git@git.flowmade.one:flowmade-one/aether.git cd aether go mod download ``` Requires NATS server for integration tests: ```bash # 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 ```bash 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. ```go // 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: ```go // 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: ```go // 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