Pupsourcing

A component-based stack for event sourcing in Go

🗃️ Event Store

Append-only event store with optimistic concurrency, aggregate versioning, and PostgreSQL-native performance.

Event Store docs →

⚙️ Worker

Distributed consumer processing with automatic leader election, rebalancing, and atomic checkpointing.

Worker docs →

🔐 Encryption

Envelope encryption for PII and secrets. Crypto-shredding for GDPR compliance. HMAC hashing for sensitive lookups.

Encryption docs →

Pupsourcing

Pupsourcing is a component-based stack for event sourcing in Go. It provides the building blocks to implement event-sourced systems backed by PostgreSQL — an event store, a distributed worker for consumer processing, and an encryption library for protecting sensitive data.

Pupsourcing does not creep into your domain layer. There are no base structs to embed, no aggregate root interfaces to implement, and no framework types leaking into your domain events. Your domain stays pure Go — pupsourcing only shows up in the infrastructure layer where persistence happens.

Quick Start

Install the event store:

go get github.com/pupsourcing/store

Append your first event:

import (
    "github.com/pupsourcing/store"
    storepostgres "github.com/pupsourcing/store/postgres"
)

eventStore := storepostgres.NewStore(storepostgres.DefaultStoreConfig())

tx, _ := db.BeginTx(ctx, nil)
defer tx.Rollback()

result, err := eventStore.Append(ctx, tx, store.NoStream(), []store.Event{{
    AggregateType: "User",
    AggregateID:   userID,
    EventID:       uuid.New(),
    EventType:     "UserRegistered",
    EventVersion:  1,
    Payload:       payload,
    Metadata:      []byte("{}"),
    CreatedAt:     time.Now(),
}})
if err != nil {
    return err
}
tx.Commit()

Read it back:

tx, _ := db.BeginTx(ctx, nil)
defer tx.Rollback()

stream, _ := eventStore.ReadAggregateStream(ctx, tx, "User", userID, nil, nil)
tx.Commit()

for _, event := range stream.Events {
    fmt.Printf("v%d %s\n", event.AggregateVersion, event.EventType)
}

The Stack

🗃️ Store

The event store is an append-only log backed by PostgreSQL. It provides optimistic concurrency control, aggregate versioning, and sequential event reading. Consumers and projections are defined as interfaces that the worker processes.

Get started with the event store →

⚙️ Worker

The worker is a distributed consumer processor. It coordinates multiple worker nodes using PostgreSQL for leader election, consumer assignment, and checkpointing. No external coordination services required.

Learn about the worker →

🔐 Encryption

The encryption library provides envelope encryption for keeping PII and secrets out of the event store. It supports crypto-shredding for GDPR compliance and key rotation for secret management.

Explore encryption →

Design Principles