Skip to content

sassy-solutions/compendium

Compendium

A pragmatic .NET framework for building event-sourced, multi-tenant SaaS applications.

CI NuGet License: MIT .NET 9

Compendium is the framework that powers Nexus, Sassy Solutions' multi-tenant platform engineering product. It distills years of building event-sourced SaaS into a small set of focused packages: DDD primitives, CQRS handlers, an event store, multi-tenancy, and ready-to-use adapters for PostgreSQL, Redis, Zitadel, and more.

Why Compendium?

  • Zero-dependency Core — Pure DDD primitives (AggregateRoot<TId>, ValueObject, Result<T>, Error) with no external dependencies beyond the .NET BCL.
  • CQRS + Event Sourcing built-in — Command/query dispatchers, event store interfaces, and a PostgreSQL adapter wired out of the box.
  • Sagas, two flavorsProcessManager<TState> for DDD-style orchestration sagas and IHandle<TEvent> for event-driven choreography sagas, each clearly named so you don't have to guess which pattern you're using. See docs/sagas.md.
  • Multi-tenancy native — Tenant context, resolution, and scoping baked into the primitives — not bolted on.
  • Result pattern everywhere — No control-flow exceptions. Every fallible operation returns Result<T> with structured Error values.
  • Modular adapters — Pick only what you need: PostgreSQL, Redis, Zitadel, Listmonk, LemonSqueezy, OpenRouter, ASP.NET Core.
  • Battle-tested in production — Powers Nexus, a multi-tenant platform engineering product.

Quick start

Install the packages you need:

dotnet add package Compendium.Core
dotnet add package Compendium.Application
dotnet add package Compendium.Adapters.PostgreSQL

Define an event-sourced aggregate:

using Compendium.Core.Domain.Primitives;
using Compendium.Core.Results;

public sealed class OrderAggregate : AggregateRoot<OrderId>
{
    private OrderStatus _status;
    private decimal _amount;

    private OrderAggregate(OrderId id) : base(id) { }

    public static Result<OrderAggregate> Create(CustomerId customerId, decimal amount)
    {
        if (amount <= 0)
            return Result.Failure<OrderAggregate>(
                Error.Validation("Order.Amount.Invalid", "Amount must be positive"));

        var order = new OrderAggregate(OrderId.New());
        order.AddDomainEvent(new OrderCreated(order.Id, customerId, amount));
        return Result.Success(order);
    }

    public void Apply(OrderCreated @event)
    {
        _status = OrderStatus.Pending;
        _amount = @event.Amount;
    }
}

Wire it up in Program.cs:

using Compendium.Application.CQRS;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Register Compendium CQRS dispatchers (command/query handlers are resolved via IServiceProvider).
builder.Services.AddScoped<ICommandDispatcher, CommandDispatcher>();
builder.Services.AddScoped<IQueryDispatcher, QueryDispatcher>();

// Register your command/query handlers, then wire the PostgreSQL event store adapter
// using the options published by Compendium.Adapters.PostgreSQL.

var app = builder.Build();

Architecture

Core (zero deps) → Abstractions → Application → Infrastructure → Adapters
                                       ↓
                              Multitenancy (cross-cutting)
  • Core — Domain primitives with no external dependencies.
  • Abstractions — Ports (interfaces) for infrastructure concerns: identity, billing, email, AI.
  • Application — CQRS orchestration: command/query handlers, dispatchers.
  • Infrastructure — Generic infrastructure concerns: projections, outbox, caching.
  • Adapters — Concrete integrations with external systems.
  • Multitenancy — Tenant resolution and scoping, usable across all layers.

Packages

Package Purpose NuGet
Compendium.Core DDD primitives, Result pattern, domain events NuGet
Compendium.Abstractions Shared infrastructure port interfaces NuGet
Compendium.Abstractions.AI AI provider contracts NuGet
Compendium.Abstractions.Billing Billing provider contracts NuGet
Compendium.Abstractions.Email Email provider contracts NuGet
Compendium.Abstractions.Identity Identity provider contracts NuGet
Compendium.Application CQRS dispatchers, handlers, pipelines NuGet
Compendium.Infrastructure Projections, outbox, infrastructure building blocks NuGet
Compendium.Multitenancy Tenant context, resolution, and scoping NuGet
Compendium.Testing Test helpers, fakes, TestContainers fixtures NuGet
Compendium.Extensions.ExternalAdapters Unified registration for external adapters NuGet
Compendium.Adapters.AspNetCore ASP.NET Core integration (middleware, auth, problem details) NuGet
Compendium.Adapters.PostgreSQL PostgreSQL event store & repositories NuGet
Compendium.Adapters.Redis Redis cache adapter NuGet
Compendium.Adapters.Zitadel Zitadel OIDC identity adapter NuGet
Compendium.Adapters.Listmonk Listmonk email adapter NuGet
Compendium.Adapters.LemonSqueezy LemonSqueezy billing adapter NuGet
Compendium.Adapters.OpenRouter OpenRouter AI provider adapter NuGet

Documentation

The full documentation site is being built at sassy-solutions.github.io/compendium (DocFX-powered). In the meantime:

  • ROADMAP.md — themes, what's next, and what's out of scope
  • CONTRIBUTING.md — build, test, conventions
  • docs/adr/ — architecture decision records
  • Source under src/ and the Nexus consumer code for end-to-end examples

Who's using Compendium?

  • Nexus — Multi-tenant platform engineering by Sassy Solutions.

Using Compendium in your project? Open a PR to add yourself to this list.

Contributing

Contributions, issues, and feedback are welcome. See CONTRIBUTING.md for guidelines on code style, commit conventions, and the development loop.

License

MIT © 2026 Sassy Solutions. See LICENSE for details.

About

A pragmatic .NET framework for event-sourced multi-tenant SaaS applications

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages