A production-ready .NET modular monolith for building multi-tenant SaaS products.
Fork it. Add your domain modules. Deploy.
Foundry provides the cross-cutting infrastructure every SaaS product needs out of the box: identity management, billing, communications, file storage, and multi-tenant data isolation. You write the business logic.
New products are created by forking Foundry and adding domain-specific modules. The base platform stays generic -- improvements to shared infrastructure can be pulled from upstream into forks.
Foundry is a modular monolith. Each module is an autonomous bounded context that follows Clean Architecture internally.
src/
├── Foundry.Api/ # Host, middleware, routing
├── Modules/
│ ├── Identity/ # Auth, users, organizations, RBAC
│ ├── Billing/ # Payments, invoices, subscriptions
│ ├── Communications/ # Email + real-time notifications
│ ├── Storage/ # File storage (S3, local)
│ └── Configuration/ # Feature flags, tenant settings
└── Shared/
├── Contracts/ # Cross-module event definitions
└── Kernel/ # Base classes, shared abstractions
Each module is structured in four layers:
| Layer | Responsibility | Dependencies |
|---|---|---|
| Domain | Entities, value objects, domain events | None |
| Application | Commands, queries, handlers, DTOs | Domain |
| Infrastructure | EF Core, Dapper, consumers, services | Application |
| API | Controllers, request/response contracts | Application |
Modules communicate through events over RabbitMQ via Shared.Contracts -- never direct references. Each module owns its own database schema.
| Module | Responsibility |
|---|---|
| Identity | Authentication, users, organizations, roles, RBAC via Keycloak 26 |
| Billing | Payments, invoices, subscription lifecycle |
| Communications | Transactional email (SMTP) and real-time push notifications (SignalR) |
| Storage | File storage abstraction (S3-compatible, local filesystem) |
| Configuration | Feature flags and tenant settings |
| Capability | Technology | Purpose |
|---|---|---|
| Auditing | Audit.NET | Automatic entity change tracking via EF Core interceptor |
| Background Jobs | Hangfire | Deferred and recurring job execution via IJobScheduler |
| Workflows | Elsa 3 | Long-running, multi-step business processes |
| Purpose | Technology |
|---|---|
| Framework | .NET 10 |
| Database | PostgreSQL 18 |
| ORM | EF Core (writes) + Dapper (reads) |
| CQRS & Messaging | Wolverine + RabbitMQ |
| Caching | Valkey (Redis-compatible) |
| Identity | Keycloak 26 |
| Real-time | SignalR |
| Validation | FluentValidation |
| Logging | Serilog |
| Tracing | OpenTelemetry |
| Testing | xUnit, Testcontainers, FluentAssertions |
cd docker && docker compose up -dThis starts PostgreSQL, RabbitMQ, Mailpit, Valkey, and Keycloak.
dotnet run --project src/Foundry.Apidotnet test # all tests
dotnet test tests/Modules/Billing/Modules.Billing.Tests # single module- Clean Architecture -- Strict dependency rules per module with domain isolation
- Domain-Driven Design -- Entities, value objects, domain events, bounded contexts
- CQRS -- Command/query separation with Wolverine as mediator
- Multi-Tenancy -- Schema-per-tenant data isolation with shared infrastructure
- Message-Based Communication -- Events over RabbitMQ, never direct references
- Keycloak Identity -- Authentication, RBAC, and user management
- Real-Time -- Push notifications via SignalR with Redis backplane
- Observability -- Serilog structured logging, OpenTelemetry tracing, Grafana dashboards
- Audit Trail -- Automatic entity change auditing via Audit.NET
- Background Jobs --
IJobSchedulerabstraction backed by Hangfire - Workflows -- Elsa 3 workflow engine for long-running processes
Schema-per-tenant with shared infrastructure. Each tenant gets isolated database schemas while sharing the same PostgreSQL instance, RabbitMQ broker, and application process. Tenant resolution happens at the middleware layer via configurable strategies (header, subdomain, or JWT claim).
New tenant onboarding is config + migration, not a deployment.
Foundry is designed for horizontal scaling from day one:
| Strategy | How |
|---|---|
| Horizontal scaling | Stateless API behind a load balancer |
| Distributed cache | Valkey/Redis for shared state and SignalR backplane |
| Competing consumers | RabbitMQ enables parallel message processing across instances |
| Durable outbox | Wolverine's transactional outbox ensures reliable messaging |
| Database scaling | PgBouncer for connection pooling, read replicas for read-heavy workloads |
| Worker separation | Separate API instances from background workers |
| Module extraction | Extract high-load modules into independent services |
- Fork this repository
- Rename namespaces from
Foundry.*toYourProduct.* - Add domain modules following the established Clean Architecture pattern
- Configure tenants
- Deploy -- the platform ships as a single deployable unit
Upstream improvements to shared infrastructure can be pulled into forks.
| Service | URL | Credentials |
|---|---|---|
| API | http://localhost:5000 | -- |
| API Docs | http://localhost:5000/scalar/v1 | -- |
| Keycloak Admin | http://localhost:8080 | See docker/.env |
| RabbitMQ | http://localhost:15672 | See docker/.env |
| Mailpit | http://localhost:8025 | -- |
| Grafana | http://localhost:3000 | admin / admin |
| Doc | Description |
|---|---|
| Developer Guide | How to work in the codebase |
| Forking Guide | Step-by-step guide for creating a new product |
| Deployment Guide | Server setup, CI/CD, and client app integration |
| Deployment Strategies | Horizontal scaling, database scaling, worker separation, module extraction |
| Architecture Reference | Single architecture and design reference |
| Keycloak Integration | Identity provider setup |
This project is licensed under the MIT License.