eventsalsa

A component-based stack for event sourcing in Go

Components

Build around the pieces you need today and grow into the rest when the system demands it.

database

eventsalsa/store

Append-only event storage with optimistic concurrency and a transaction-first API.

  • PostgreSQL-backed
  • Append-only
  • Optimistic concurrency
Read more →
hub

eventsalsa/worker

Run async consumers and projections across one or more worker processes, with PostgreSQL-backed rebalancing.

Read more →
lock

eventsalsa/encryption

Standalone envelope encryption for PII and secrets, with crypto-shredding and HMAC hashing for sensitive lookups.

Read more →

Why eventsalsa?

Keep the architecture explicit, the runtime PostgreSQL-native, and the domain model free of framework ownership.

extension

Component-based

Use only the modules you need. The store, worker, and encryption packages can be adopted independently.

account_tree

No infrastructure creep

eventsalsa does not require aggregate root base types or framework-owned structs in your domain model.

sync_alt

Optimistic concurrency

Expected versions make concurrent writes explicit and keep aggregate updates honest.

database

PostgreSQL-driven

The store and worker are built on PostgreSQL - no need for a 3rd party message broker.

schema

Domain-Driven Design

Versioned events support rich domain modelling while keeping the model explicit and free from framework-owned types.

view_quilt

Clean architecture

Keep event infrastructure at the edges while the application model remains plain Go.

eventsalsa/store

eventsalsa/store gives you an append-only event log, optimistic concurrency, and a transaction-first API without prescribing your domain model.

Install terminal
go get github.com/eventsalsa/store
  • check Append and read aggregate streams in a PostgreSQL-backed event store.
  • check Use optimistic concurrency through explicit expected versions.
  • check Control transaction boundaries yourself with the *sql.Tx you already have.
main.go
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}
worker.go
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

eventsalsa/worker runs async consumers and projections across one or more worker processes, with PostgreSQL-backed assignment and rebalancing.

Install terminal
go get github.com/eventsalsa/worker
  • check Start with one worker process and add more when you want consumer assignments split out.
  • check Keep coordination in PostgreSQL while the leader rebalances consumers across live workers.
  • check Build consumers on eventsalsa/store/consumer without introducing a separate broker first.