eventsalsa/store
Append-only event storage with optimistic concurrency and a transaction-first API.
Read more →Build around the pieces you need today and grow into the rest when the system demands it.
Append-only event storage with optimistic concurrency and a transaction-first API.
Read more →Run async consumers and projections across one or more worker processes, with PostgreSQL-backed rebalancing.
Read more →Standalone envelope encryption for PII and secrets, with crypto-shredding and HMAC hashing for sensitive lookups.
Read more →Keep the architecture explicit, the runtime PostgreSQL-native, and the domain model free of framework ownership.
Use only the modules you need. The store, worker, and encryption packages can be adopted independently.
eventsalsa does not require aggregate root base types or framework-owned structs in your domain model.
Expected versions make concurrent writes explicit and keep aggregate updates honest.
The store and worker are built on PostgreSQL - no need for a 3rd party message broker.
Versioned events support rich domain modelling while keeping the model explicit and free from framework-owned types.
Keep event infrastructure at the edges while the application model remains plain Go.
eventsalsa/store gives you an append-only event log, optimistic
concurrency, and a transaction-first API without prescribing your domain model.
go get github.com/eventsalsa/store *sql.Tx you already have. import ( "time" "github.com/eventsalsa/store" "github.com/eventsalsa/store/postgres" "github.com/google/uuid")s := postgres.NewStore(postgres.DefaultStoreConfig())event := store.Event{ AggregateType: "User", AggregateID: userID, EventID: uuid.New(), EventType: "UserRegistered", EventVersion: 1, Payload: payload, Metadata: []byte(`{}`), CreatedAt: time.Now(),}if _, err := s.Append(ctx, tx, store.NoStream(), []store.Event{event}); err != nil { return err} type AccountProjection struct{}func (p *AccountProjection) Name() string { return "account_projection"}func (p *AccountProjection) AggregateTypes() []string { return []string{"Account"}}w := worker.New( db, eventStore, []consumer.Consumer{&AccountProjection{}}, worker.WithBatchSize(100), worker.WithPollInterval(500 * time.Millisecond),)if err := w.Start(ctx); err != nil { return err} eventsalsa/worker runs async consumers and projections across one or
more worker processes, with PostgreSQL-backed assignment and rebalancing.
go get github.com/eventsalsa/worker eventsalsa/store/consumer without introducing a separate broker first.