Backend Architecture

Program.cs anatomy, middleware pipeline, DI service map, module registration pattern, and controller catalog.

The SCRIPE backend is a .NET 10 Modular Monolith with 288 lines in Program.cs that wire together 16 service registrations, 10 middleware components, and 18 REST controllers. This page dissects every layer of the backend architecture.

Program.cs Anatomy

Program.cs is the application's entry point and wiring center. It detects the deployment mode, registers services in a specific order, and builds the middleware pipeline. The file follows a clear 5-section structure.

Program.cs — Simplified Architecture (288 lines)C#
var builder = WebApplication.CreateBuilder(args);

// ─── 1. Environment Detection ───────────────────────────
var moduleName = Environment.GetEnvironmentVariable("MODULE_NAME") ?? "";
var isMonolith = string.IsNullOrEmpty(moduleName);
var isGateway = moduleName.Equals("Gateway", StringComparison.OrdinalIgnoreCase);

// ─── 2. Core Infrastructure (must come first) ───────────
builder.Services.AddInfrastructureServices(builder.Configuration);
builder.Services.AddCorsConfiguration(builder.Configuration);
builder.Services.AddRateLimitingConfiguration();
builder.Services.AddCoreInfrastructure(builder.Configuration);

// ─── 3. Module Registration (guarded by mode) ───────────
var handlerAssemblies = new List<Assembly>();
if (isMonolith || moduleName == "Identity")
{
    handlerAssemblies.Add(typeof(Identity.Application.DependencyInjection));
    builder.Services.AddIdentityModule(builder.Configuration);
}

// ─── 4. Application Layer (needs module assemblies) ─────
builder.Services.AddCoreApplication(handlerAssemblies);

// ─── 5. Build & Configure Pipeline ─────────────────────
var app = builder.Build();
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseMiddleware<AuditableMiddleware>();
app.UseRateLimiter();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

Middleware Pipeline

The middleware pipeline processes every HTTP request in a specific order. Each middleware can short-circuit the pipeline (e.g., rate limiter returns 429, auth returns 401). Order matters changing it can break security.

Middleware Pipeline (Order Matters)
1. CORS
2. HSTS (Production)
3. Exception Handler
4. Rate Limiter
5. Request Logging
6. Static Files
7. Authentication
8. Authorization
9. Response Caching
10. Compression (Brotli+Gzip)

DI Service Map

The following table shows all major service interfaces, their implementations, lifetimes, and where they are registered. Understanding this map is essential for debugging and extending the system.

Service InterfaceImplementationLifetimeRegistered In
ICurrentUserCurrentUserScopedCoreInfrastructure
IApiServiceApiServiceScopedCoreInfrastructure
IAuditServiceAuditServiceScopedCoreInfrastructure
ICacheServiceMemoryCacheService / RedisCacheServiceSingletonCoreInfrastructure
IEmailServiceSmtpEmailServiceScopedCoreInfrastructure
IBlobStorageServiceLocalBlobStorage / AzureBlobStorageSingletonBlobStorage
IAdminRepositoryAdminRepositoryScopedIdentityModule
IUserRepositoryUserRepositoryScopedIdentityModule
IRoleRepositoryRoleRepositoryScopedIdentityModule
ITenantRepositoryTenantRepositoryScopedIdentityModule
IMenuRepositoryMenuRepositoryScopedIdentityModule

Module Registration Pattern

Every new module follows the same DI registration pattern. The AddXxxModule() extension method registers the module's DbContext, repositories, services, and module registration marker.

Identity Module — DependencyInjection.cs PatternC#
public static class DependencyInjection
{
    public static IServiceCollection AddIdentityModule(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        // 1. DbContext registration (multi-provider)
        services.AddDbContext<IdentityDbContext>(options =>
        {
            var provider = configuration["DatabaseProvider"];
            switch (provider)
            {
                case "SqlServer":
                    options.UseSqlServer(connectionString);
                    break;
                case "PostgreSQL":
                    options.UseNpgsql(connectionString);
                    break;
                case "Oracle":
                    options.UseOracle(connectionString);
                    break;
            }
        });

        // 2. Repository registrations
        services.AddScoped<IAdminRepository, AdminRepository>();
        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IRoleRepository, RoleRepository>();

        // 3. Module-specific services
        services.AddScoped<IPermissionService, PermissionService>();
        services.AddScoped<IJwtService, JwtService>();

        // 4. Module registration (for runtime introspection)
        services.AddSingleton<IModuleRegistration, IdentityModuleRegistration>();

        return services;
    }
}

Controllers

ControllerBase RouteEndpointsAuth Required
AuthController/api/v1/authLogin, Refresh, Logout, Verify2FAPartial
AdminController/api/v1/adminCRUD + Block + ImpersonateYes
UserController/api/v1/usersCRUD + Profile + AvatarYes
RoleController/api/v1/rolesCRUD + Assign PermissionsYes
TenantController/api/v1/tenantsCRUD + Settings + LogoYes
PermissionController/api/v1/permissionsList + Categories + AssignYes
MenuController/api/v1/menusCRUD + Reorder + TreeYes
AuditController/api/v1/auditSearch + Export + StreamYes
DashboardController/api/v1/dashboardStats + Charts + FeedYes
FileController/api/v1/filesUpload + Download + DeleteYes
RecycleBinController/api/v1/recycle-binList + Restore + PurgeYes
NotificationController/api/v1/notificationsList + Read + SettingsYes
SettingsController/api/v1/settingsGet + Update + ResetYes
HealthController/healthLiveness + ReadinessNo