Backend ADRs — Architecture Decision Records
Architecture Decision Records (ADRs) document significant technical decisions made during the development of Granit.
Each ADR follows a consistent template: Context, Decision, Evaluated Alternatives, Justification, and Consequences.
ADR index
Section titled “ADR index”| # | Title | Status | Date | Scope |
|---|---|---|---|---|
| 001 | Observability Stack — Serilog + OpenTelemetry | Accepted | 2026-02-21 | Granit.Observability |
| 002 | Redis via StackExchange.Redis — Distributed Cache | Accepted | 2026-02-21 | Granit.Caching |
| 003 | Testing Stack — xUnit v3, NSubstitute and Bogus | Accepted | 2026-02-21 | granit-dotnet |
| 004 | Asp.Versioning — REST API Versioning | Accepted | 2026-02-22 | Granit.Http.ApiVersioning |
| 005 | Wolverine + Cronos — Messaging, CQRS and Scheduling | Accepted | 2026-02-22 | Granit.Wolverine |
| 006 | FluentValidation — Business Validation Framework | Accepted | 2026-02-24 | Granit.Validation |
| 007 | Testcontainers — Containerized Integration Tests | Accepted | 2026-02-24 | Integration Tests |
| 008 | SmartFormat.NET — CLDR Pluralization | Accepted | 2026-02-26 | Granit.Localization |
| 009 | Scalar.AspNetCore — Interactive API Documentation | Accepted | 2026-02-26 | Granit.Http.ApiDocumentation |
| 010 | Scriban — Text Template Engine | Accepted | 2026-02-27 | Granit.Templating.Scriban |
| 011 | ClosedXML — Excel Spreadsheet Generation | Accepted | 2026-02-27 | Granit.DocumentGeneration.Excel |
| 012 | PuppeteerSharp — HTML to PDF Rendering | Accepted | 2026-02-28 | Granit.DocumentGeneration.Pdf |
| 013 | Magick.NET — Image Processing | Accepted | 2026-02-28 | Granit.Imaging.MagickNet |
| 014 | Migrate FluentAssertions to Shouldly | Accepted | 2026-02-28 | granit-dotnet |
| 015 | Sep — High-Performance CSV Parsing | Accepted | 2026-03-01 | Granit.DataExchange.Csv |
| 016 | Sylvan.Data.Excel — Streaming Excel File Reading | Accepted | 2026-03-01 | Granit.DataExchange.Excel |
| 017 | DDD Aggregate Root & Value Object Strategy | Accepted | 2026-03-19 | granit-dotnet (all modules) |
| 018 | FusionCache — Caching Provider | Accepted | — | Granit.Caching |
| 019 | User Lookup — Dual Mode | Accepted | — | Granit.Identity |
| 020 | Declarative Definitions Placement (Query & Export) | Accepted | 2026-04-18 | Granit.QueryEngine, Granit.DataExchange, all modules |
| 021 | Privacy Data Export — Framework Defaults | Accepted | 2026-04-19 | Granit.Privacy, Granit.Privacy.BlobStorage, Granit.Privacy.EntityFrameworkCore |
| 022 | ICommandSender + Module Naming — No Technology Suffix on Domain Modules | Accepted | 2026-04-20 | All business modules, Granit.Commands, Granit.Wolverine |
| 023 | Tenant-aware role lookup | Accepted | 2026-04-22 | Granit.Identity.Local, Granit.Identity.Local.AspNetIdentity |
| 024 | Shared-connection EF Core transaction for role orchestration | Accepted | 2026-04-22 | Granit.Identity.Local.AspNetIdentity, Granit.Authorization.EntityFrameworkCore, Granit.OpenIddict.EntityFrameworkCore, Granit.Persistence.EntityFrameworkCore |
| 025 | Keycloak client-role distinction and boot-time sync | Accepted | 2026-04-22 | Granit.Identity, Granit.Identity.Federated.Keycloak |
| 026 | Entra ID App Role distinction and boot-time sync | Accepted | 2026-04-22 | Granit.Identity.Federated.EntraId |
| 027 | Cognito app-client group sync via naming-prefix convention | Accepted | 2026-04-23 | Granit.Identity.Federated.Cognito |
| 028 | Unified Data Lookup for QueryEngine Filters and Form Dropdowns | Accepted | 2026-04-23 | Granit.DataLookup.*, Granit.QueryEngine.*, Granit.ReferenceData.*, @granit/data-lookup, @granit/react-data-lookup |
| 029 | Client-role sync — opt-in orphan cleanup policy | Accepted | 2026-04-23 | Granit.Authorization.*, Granit.Identity.Federated.* |
| 030 | Client-role sync — scheduled re-sync via Granit.BackgroundJobs | Accepted | 2026-04-23 | Granit.Identity.Federated.*.BackgroundJobs |
| 031 | Client-role write operations on IIdentityClientRoleManager | Accepted | 2026-04-23 | Granit.Identity, Granit.Identity.Federated.* |
| 032 | Granit.Catalog with Product as the shared billing aggregate | Accepted | 2026-04-24 | Granit.Catalog.*, Granit.Metering, Granit.Subscriptions, Granit.Invoicing |
| 033 | Metering hybrid — lifecycle, CountDistinct, recompute, backfill, deprecate | Accepted | 2026-04-25 | Granit.Metering.* |
| 034 | Subscriptions — pricing tiers, phases, discounts, price overrides | Accepted | 2026-04-25 | Granit.Subscriptions, Granit.Subscriptions.EntityFrameworkCore, Granit.Subscriptions.Endpoints |
| 035 | Granit.CustomerBalance ↔ ORB Credits term-by-term mapping | Accepted | 2026-04-25 | Granit.CustomerBalance.* |
| 036 | Invoicing line item source + product convention | Accepted | 2026-04-25 | Granit.Invoicing.*, Granit.Subscriptions, Granit.Metering |
| 037 | Party Merge Framework — Mergeable primitive + cross-module rewriters | Accepted | 2026-04-27 | Granit.Mergeable, Granit.Mergeable.EntityFrameworkCore, Granit.Parties, Granit.Parties.Mergeable, Granit.Parties.Endpoints |