Calcifer.Forge
The .NET 8 microservice foundation with built‑in licensing, feature gating, seat control, and modular architecture. Everything you need to turn an API into a monetisable product.
# Overview
Calcifer.Forge is not just a template — it's the missing layer between your software and your business model. While most .NET templates give you CRUD endpoints and basic auth, Forge ships with the infrastructure that actually makes software sellable.
Built on .NET 8 LTS with Clean Architecture principles and vertical slice organisation, Forge provides a production‑ready foundation that includes:
- Authentication & authorisation (JWT + Identity)
- Licensing engine (key generation, validation, expiry, machine binding)
- Feature gating with declarative attributes
- Seat control (concurrent usage limits)
- Modular feature architecture (plug‑and‑play modules)
- Background jobs (Hangfire) and event bus
- OpenAPI / Swagger out of the box
💡 Design Philosophy
Every feature in Forge exists because a real developer hit a wall trying to monetise their software. No vanity features. No "nice to have." Every module solves a real business problem.
# Architecture
Forge follows Clean Architecture with a practical twist — vertical slices within each layer. This means features are self‑contained, testable, and deployable independently.
Layer breakdown
Core
Entities, interfaces, domain logic. Zero external dependencies.
Application
Use cases, DTOs, validators. Orchestrates domain operations.
Infrastructure
EF Core, Identity, email, external APIs.
API
Minimal API endpoints, middleware, filters.
Modules
Feature modules with self‑contained routes and logic.
Licensing
License engine, activation, feature resolver, seat manager.
Request flow
Client → API Gateway (Kong/YARP) → Authentication Middleware (JWT) → License Validation Middleware → Feature Gate Filter → Module Handler → ResponseEach module can define its own endpoints, validators, and dependencies — but they all share the same licensing and gating pipeline.
# Licensing Engine
The licensing engine is the heart of Forge's monetisation infrastructure. It handles the complete lifecycle — creation, validation, activation, expiration, and revocation — with no third‑party dependencies.
License Key Generation
Generate cryptographically secure keys bound to tiers and feature sets. Time‑limited or perpetual.
Activation & Validation
Activate against machine IDs. Validates expiry, features, tier, and seats in one call.
Seat Control
Limit concurrent activations per license. Blocks new activations when seats are exhausted.
Usage Tracking
Monitor activation patterns and feature usage across your customer base.
API reference
{
"licenseKey": "LIC-PRO-XXXX-XXXX",
"machineId": "DESKTOP-A1B2C3"
}{
"activated": true,
"tier": "professional",
"features": ["analytics", "export", "multi-tenant"],
"seatsRemaining": 4,
"expiresAt": "2027-04-01T00:00:00Z",
"machineIdBound": "DESKTOP-A1B2C3"
}🔐 Security note
License keys are generated using System.Security.Cryptography with a secret salt. Machine IDs are SHA‑256 hashed before storage – we never store raw machine identifiers.
# Feature Gating
Feature gating in Forge goes beyond simple role checks. It operates at the endpoint level using custom attributes, allowing you to control which license tiers can access which features — declaratively.
[RequireFeature("analytics")]
[RequireFeature("export")]
public async Task<IResult> ExportAnalyticsReport(
IAnalyticsService analytics,
ILicenseContext license)
{
var report = await analytics.GenerateReport(license.TenantId);
return Results.File(report.ToCsv(), "text/csv");
}Available attributes
| Attribute | Description |
|---|---|
[RequireFeature] | Requires one or more features (AND logic). |
[RequireAnyFeature] | Requires at least one of the listed features (OR logic). |
[RequireSeat] | Consumes a seat – blocks if no seats left. |
[RequireLicenseTier] | Checks license tier (basic, pro, enterprise). |
How it works under the hood
A custom IAuthorizationFilter reads the attributes, resolves the current license from HttpContext.User (via a claim), and checks feature membership using a cached license resolver. If validation fails, a 403 Forbidden is returned immediately — no controller code runs.
# Seat Control
Seat control limits concurrent usage of a license key. Each activation consumes one seat; when the user logs out or the machine is deactivated, the seat is freed.
// Seat management service
public class SeatManager : ISeatManager
{
public async Task<bool> TryOccupySeatAsync(string licenseKey, string machineId)
{
var license = await _licenseRepo.GetByKeyAsync(licenseKey);
var activeSeats = await _seatRepo.CountActiveSeatsAsync(licenseKey);
if (activeSeats >= license.SeatLimit) return false;
await _seatRepo.AddAsync(new Seat(licenseKey, machineId));
return true;
}
}Seat limits are enforced at the API middleware level, so even custom endpoints cannot bypass seat checks.
# Tech Specifications
# Configuration
All settings are in appsettings.json and can be overridden by environment variables (using the __ delimiter).
{
"Licensing": {
"Salt": "your-secret-salt-here",
"DefaultTier": "basic",
"AllowOfflineValidation": false,
"SeatTimeoutMinutes": 720
},
"FeatureGating": {
"CacheDurationSeconds": 300,
"StrictMode": true
},
"Jwt": {
"Issuer": "calcifer-forge",
"Audience": "calcifer-api",
"ExpiryMinutes": 60
}
}# Getting Started
Clone the repository
Start by cloning the Forge template.
git clone https://github.com/calcifer-shop/forge.git my-project
cd my-projectConfigure your database
Update appsettings.json with your connection string.
"ConnectionStrings": { "Default": "Server=localhost;Database=MyApp;Trusted_Connection=true;" }Run migrations & seed data
Apply migrations and seed roles, admin user, and reference data.
dotnet ef database update
dotnet run --seedStart building
The API runs at https://localhost:5001. Swagger at /swagger.
dotnet run# Best Practices
- Always validate licenses at the middleware level – never trust client‑side checks.
- Cache feature sets per user to avoid database round trips on every request.
- Use the module system to isolate business logic – each module can be deployed independently.
- Run the seed command during development to populate roles and an admin user.
- Enable Swagger and document all feature‑gated endpoints with OpenAPI extensions.
# FAQ
Can I use Forge without the licensing engine?
Yes – you can disable the license validation middleware in Program.cs. But then it's just a normal .NET template.
How do I create a new feature module?
Run dotnet new calcifer-module -n MyModule (custom template included). It will generate endpoints, validators, and a feature flag placeholder.
Does Forge support multi‑tenancy?
Built‑in multi‑tenancy is on the roadmap. For now, you can implement it via a tenant resolver middleware and inject ITenantContext.