Built by engineers, for engineers

Architecture, security, and operations — laid out for the people who will integrate with this platform.

Engineering at Clever Initiative

Every architectural decision is intentional. Nothing is included by accident.

This page is for the engineers who will live with this platform — the ones who integrate against it, build modules on top of it, and sign off on architecture reviews. We will not soften anything for marketing here.

What follows is the truth about how Clever Initiative is engineered: the layering, the data isolation guarantees, the runtime module loading, the security model, the test discipline, and the operational shape. Every claim below is enforced in code, in CI, or in a hard boundary that cannot be silently crossed.

  • .NET 10 + Angular 21 — both intentionally on their latest stable major
  • Clean Architecture enforced at the project-reference level, not just by convention
  • Module marketplace loaded into private AssemblyLoadContexts with cryptographic signature verification

Ten engineering guarantees you inherit on day one

Each one is enforced in the code, in CI, or by the type system — so the platform's behaviour stays predictable as your business scales and as modules evolve around it.

01

Compile-time-enforced Clean Architecture

Domain → Application → Infrastructure → API dependency arrows are project-level references. A handler that tries to reach into infrastructure fails the build — there are no silent shortcuts in your tenant, and behaviour stays predictable across every endpoint.

02

Uniform CQRS request pipeline

Every command and query flows through the same logging → validation → cache → transaction pipeline. Behaviour is uniform across every endpoint and observability hooks attach in one place, so your integrations get consistent timing, validation, and error semantics.

03

Database-per-tenant by architecture

Each tenant runs on its own dedicated database. No shared tables, no row-level filters — a query bug cannot leak across customers because the data is not co-located in the first place. Cross-tenant access is impossible by construction, not by configuration.

04

Projection-based, paginated reads

Read paths project directly to DTOs and every list endpoint is paginated by contract with a hard upper bound. The platform cannot accidentally return an unbounded result set against your data — large tables stay cheap to query.

05

Authorization checked twice

Every protected endpoint checks permissions at the HTTP boundary and again inside the handler. A misconfigured route or a missed attribute cannot grant access on its own, so a permissions regression has to defeat two layers, not one.

06

Outbox-based eventing — no lost events

Cross-system events are persisted in the same database transaction as the state change and published asynchronously. A crash mid-flight cannot leave your tenant in an inconsistent state; consumers are idempotent so retries are safe by design.

07

Append-only, online schema migrations

Released migrations are never edited — every change ships as a new forward migration, runs per tenant without a maintenance window, and never blocks other tenants on the same host. Upgrades happen on your schedule, not ours.

08

Versioned APIs, predictable evolution

Every endpoint is versioned via Asp.Versioning. Breaking changes are explicit and never silent — older versions keep working for your existing integrations until you choose to migrate, and deprecations are announced in advance.

09

RFC 7807 problem responses everywhere

Validation errors, conflicts, business-rule violations, and unexpected failures all return typed problem responses with a plain-language detail. Your integrations get a stable, machine-readable error contract instead of stack traces or SQL fragments.

10

Integration tests against real infrastructure

Every release runs the full-solution test suite against containerised SQL Server, Redis, and RabbitMQ in CI — no mocked databases pretending to validate production behaviour. What ships has already been exercised end-to-end on real engines.

Backend architecture

Clean Architecture, .NET 10

The dependency arrows in the diagram below are enforced at the project-reference level. Cross them and the build fails — there is no convention-only layer policing here.

Domain
Application
Infrastructure
API (Presentation)
Composition root
01
DomainInnermost · 0 dependencies
Entities, value objects, domain events, domain exceptions, DomainConstants. Nothing else lives here.
02
ApplicationUse cases
Depends only on Domain. Commands, queries, MediatR handlers, FluentValidation validators, Mapperly mappers, MediatR pipeline behaviors.
03
InfrastructureAdapters
Depends on Application + Domain. EF Core 10, Redis, MassTransit, JWT, BCrypt, repositories. Implements contracts the Application layer defines.
04
API (Presentation)Composition root
Depends on all three. Controllers, middleware, DI composition, Scalar OpenAPI, RFC 7807 ProblemDetails error mapping.

MediatR pipeline (outer → inner)

Every command flows through this pipeline. Queries skip the transaction step.

01
LoggingBehavior
Logs command name and elapsed milliseconds. Never logs payload contents.
02
ValidationBehavior
Runs all registered FluentValidation validators. Throws ValidationException → 400 with field-level errors dictionary.
03
CacheInvalidationBehavior
Marks cache keys dirty after successful commands. Pattern-based invalidation via ICacheService (Redis in prod, in-memory in dev).
04
TransactionBehavior
Wraps each ICommand in an EF Core transaction. SaveChanges happens inside; integration events publish only after commit.
Multi-tenancy

Database-per-tenant. Complete data isolation. No shortcuts.

Database-per-tenant is an architectural commitment, not a configuration option. Each tenant gets its own SQL Server database. There are no shared tables and no row-level filters substituting for real isolation.

What this guarantees

  • Physical separation of customer data — never co-mingled, ever
  • Per-tenant migrations run independently, online, without affecting other tenants
  • Compliance contracts can be signed knowing data physically lives in one tenant boundary
  • A bug in row-level filtering cannot leak across tenants — there are no row-level filters
  • Backup, restore, and disaster recovery happen per tenant, with per-tenant RPO/RTO

How tenant credentials are protected

  • Held in a managed key vault — never in the application database, never in source. Zero credential material lives anywhere your code path or your data path can reach.
  • AES-256-encrypted before they are written, even inside the vault — so a compromise of the vault alone does not yield usable credentials.
  • Fetched in-process only when needed, never logged at any level, never returned in any API response, never serialised into telemetry.

Tenant resolution chain — 5 steps, first match wins

On every request, the platform identifies which tenant the request belongs to via this fallback chain. Resolution happens once per request, in middleware ordered after authentication so the JWT claim is available.

1
JWT tenant_id claim
If the access token carries tenant_id, that is authoritative.
2
X-Tenant-Id HTTP header
Platform admins acting on a specific tenant set this header explicitly.
3
Custom domain match
A tenant's own domain — app.theirclient.com — is mapped at startup and matched per request.
4
Platform subdomain
{slug}.cleverinit.com routes to the matching tenant.
5
?tenant= query string
Development-only. Disabled in production. The chain falls through to a 401 if no resolution succeeds.
Identity & Access

Layered authentication and authorization

Authentication and authorization are layered. Every request passes through both, and authorization is checked twice — at the HTTP boundary and again in the handler.

Short-lived JWT access tokens

15-minute HMAC-SHA256 access tokens carry the user's full permission set as a string-array claim. Authorization decisions are O(1) in-memory lookups, so per-request cost stays flat as your permission catalogue grows.

Refresh tokens with rotation and revocation

256-bit random refresh tokens, 7-day TTL, persisted server-side and rotated on every use. A compromised refresh token can be revoked centrally and the short-lived access token closes the window within minutes.

BCrypt password hashing, tuned annually

Cost factor 12 — roughly 100 ms per hash on production hardware. The cost is reviewed every year so credentials hashed today stay expensive to crack tomorrow, even as hardware improves.

Two-factor authentication

OTP delivered via email or SMS, configurable per tenant. Built on Otp.NET with rolling time windows; codes are never logged or echoed in any response.

Granular, named permission model

Every protected action is gated by a named permission such as Users.View or Modules.Install. Permissions are seeded centrally, assignable to roles in the admin panel, and visible to tenant administrators — there are no hidden privileges.

Account protection by default

Account lockout after five failed attempts, audit trail of every authentication event, and tenant-scoped revocation paths so a compromise in one tenant never propagates to another.

Event processing

The outbox pattern — at-least-once with effectively-once UX

Business operations that span system boundaries — sending a welcome email, provisioning a module database, notifying a third-party webhook — are dispatched through events. The platform never makes a synchronous call to an external service in the request path.

01
STEP 01
State change in DB transaction
Aggregate root mutates state inside ApplicationDbContext.SaveChangesAsync().
02
STEP 02
Outbox row, same transaction
Integration events for cross-process delivery are written to the OutboxMessages table inside the same DB transaction. Atomic with the state change.
03
STEP 03
OutboxProcessorWorker publishes
Background worker polls every 5 seconds, batches up to 50 events, publishes them via MassTransit to RabbitMQ. Marks rows as processed on success.
04
STEP 04
Idempotent consumers
Consumers are written so running the same event twice has the same effect as running it once. At-least-once delivery becomes effectively-once for the end user.
Module marketplace

Modules are guests in the host process

Modules ship as signed .tar.gz artifacts. The host loads each module's assemblies into a private AssemblyLoadContext. Tenants install modules independently into their own dedicated databases. No host redeploy is required to make a new module available, and no host redeploy is required when a tenant installs one.

Publish — a host event, one time per module version

A module is published through a signed pipeline that produces a versioned, signed artifact. The host verifies the RSA-4096 signature, extracts the artifact, loads its assemblies into an isolated context, and registers the manifest. The module is now available in the marketplace — but no tenant has started using it yet, and no host redeploy was needed.

Install — a tenant event, one click per customer

A tenant administrator installs the module from the marketplace. The platform runs the module's migrations against that tenant's dedicated database, registers its permissions, and the feature becomes live for the tenant's users on their next request. Installation does not load any new code — that already happened at publish time — so each tenant controls exactly which features run inside its own database.

Hard boundaries that protect your tenant

Modules communicate only via integration events
Modules never share a database context, never call each other directly, and never read each other's tables. They cooperate through typed integration events on a defined contract — so one module misbehaving cannot silently corrupt another module's data.
Modules see only the public contract surface
Modules reference the platform's abstractions package and standard frameworks (EF Core, MediatR, FluentValidation, and so on) — never internal implementation assemblies. The host can be refactored without breaking any installed module.
Isolated assembly load contexts
Each module loads into its own private AssemblyLoadContext. A module's dependencies cannot conflict with the host or with other modules, and a misbehaving module can be hot-replaced or uninstalled without restarting the platform.
Uninstall is non-destructive by design
Uninstalling a module removes its navigation entries and permissions from the active interface immediately, but the tenant data it created — CRM contacts, payment records, chat history — is preserved. Reinstalling restores access to that state.
Frontend architecture

Angular 21, zoneless, signal-first

The admin panel is intentionally on the latest Angular stable. Every architectural decision pushes toward signal-based reactivity and OnPush change detection — faster renders, smaller bundles, and a stack that stays hireable in the years ahead.

Zoneless, signal-driven change detection

The panel runs with provideZonelessChangeDetection() — zone.js is never imported. Render passes are driven precisely by signal reads, not by broad zone interception, so the UI stays responsive even as feature surface grows.

Standalone components, OnPush by default

Every component is standalone with ChangeDetectionStrategy.OnPush. No NgModules, no implicit re-renders — smaller bundles, faster cold starts, and a render model that scales to large admin surfaces without slowdowns.

Signal-based, feature-scoped state

Shared state lives in NgRx SignalStore instances scoped to the host component, never global. Cross-feature coupling stays explicit, and state bleed between modules is structurally impossible — important when third-party modules run inside the panel.

Accessible, consistent UI primitives

Every page in the panel and every module is built from the same shared library of headers, tables, modals, forms, and empty states. Accessibility, keyboard handling, and behaviour stay uniform — no off-spec inputs sneaking in through one module.

Module Federation for runtime extension

Each module's frontend ships as a federated remote that the host loads on demand. New modules light up under /m/<slug>/... without redeploying the panel, and every shared dependency is exact-pinned to the host's version so there is no silent skew at runtime.

Modern test stack

Vitest for unit and component tests in zoneless mode, Playwright for end-to-end journeys across the full panel. Tests run in the same browsers your users do — no legacy runners drifting away from real behaviour.

Tech stack

Pinned, deliberate, boring

Versions are pinned. Adding a new library requires explicit approval. Below is what is in the solution today.

Backend

.NET 10 · Clean Architecture · CQRS
  • .NET 10 · C# 13 · ASP.NET Core
  • EF Core 10 · SQL Server 2022
  • MediatR 14 · FluentValidation 12
  • Riok.Mapperly 4.3 · Ardalis.Specification 9.3
  • StackExchange.Redis 2.12 · MassTransit + RabbitMQ 8.5
  • BCrypt.Net-Next 4.1 · Otp.NET 1.4 · SendGrid 9.29 · Twilio 7.7 · Scalar OpenAPI 2.6

Frontend

Angular 21 · Signals-first · Zoneless
  • Angular 21 · TypeScript 5.7
  • NgRx SignalStore · Angular Signals
  • Metronic Tailwind (pre-built) · KTui · Keenicons
  • @ngx-translate/core (en · nl · de)
  • Vitest + Playwright (Karma / Jasmine / Jest banned)
  • esbuild + Vite build pipeline

Platform & DevOps

Docker · Kubernetes · GitHub Actions
  • Docker · docker-compose for local development
  • GitHub Actions for CI/CD across api, panel, and modules
  • Azure Kubernetes Service (AKS) as production target
  • Health checks, diagnostics, OpenTelemetry-ready observability
  • Credentials held in a managed key vault, AES-256-encrypted at rest
  • HTTPS in transit, OWASP-aligned hardening, RFC 7807 errors
Quality & operations

Quality gates that ship every release

Every release passes these gates before any tenant sees it. CI enforces what code review cannot, and code review enforces what CI cannot.

Continuous integration on every commit

Every push runs build, lint, and the full test suite end-to-end. Releases are cut only from branches that have gone fully green — there is no green-on-laptop-only path to production.

Tested across the full pyramid

The full-solution test suite executes domain, application, infrastructure, and API tests on every commit. Coverage floors are enforced in CI: Domain > 95%, Application > 85%, Infrastructure and API > 70%.

Real-infrastructure integration tests

Integration tests run against containerised SQL Server, Redis, and RabbitMQ — not mocks. Behaviour that depends on real query plans, real cache evictions, or real message brokers is verified in CI before it can ship to your tenant.

Module manifest / code parity

Every module ships a parity test that fails the build if a controller asks for a permission the manifest does not declare. Misaligned permission strings cannot ship past CI — the failure is loud and immediate, not silent in production.

Immutable audit log by interceptor

Every meaningful state change is captured automatically — before/after values, actor, timestamp, and source IP. Sensitive fields are excluded by allow-list, and audit rows are append-only once written, so the history of your tenant is tamper-evident.

RFC 7807 problem responses with plain-language detail

Domain exceptions map to typed problem responses: ValidationException → 400 with field-level errors, EntityNotFound → 404, Duplicate → 409, BusinessRuleViolation → 422. The detail string is always a complete sentence — never a class name, never a SQL fragment, never an internal stack frame.

DevOps & signing

Operations, CI/CD, and the module signing pipeline

Operations are deliberate. The signing pipeline is the most operationally sensitive part of the platform — it gates every module that ever loads into a production tenant.

Docker locally, Kubernetes in production

Local development runs on docker-compose for a one-command spin-up; production runs on Azure Kubernetes Service. Health checks, readiness probes, and graceful shutdown are first-class — rolling updates do not drop in-flight requests.

GitHub Actions across api, panel, and modules

Per-repository workflows handle the platform; modules share one reusable workflow that builds, signs, and publishes the artifact in a single deterministic step. No bespoke per-module pipelines to drift out of sync.

RSA-4096 module signing

Every module artifact is signed with a private key held only in repository secrets and verified by the host with a bundled public key at load time. Unsigned or tampered artifacts cannot load in production — period.

CI-enforced module versioning

On a v* tag push, CI asserts that the module's manifest version matches the tag exactly. Version skew between manifest and release fails the build with a clear error, so installed-version drift cannot reach a tenant.

Release-safe schema migrations

Every entity or configuration change ships an EF migration in the same commit. Migrations are append-only after release — never edited, only superseded — so your tenant database has a deterministic, auditable history.

Observability-ready by default

Structured logging via Microsoft.Extensions.Logging, OpenTelemetry-ready spans, and correlation IDs propagated through the request pipeline and MassTransit consumers. Sensitive payloads — PII, OTP codes, webhook bodies, and any credential material — are scrubbed before they reach any sink.

Security & compliance

Security is engineered before code, reviewed before merge, and tested before deployment

A dedicated security team owns the platform's security posture full-time — not a part-time responsibility distributed across feature engineers. Every change, from a one-line config tweak to a brand-new module, goes through the same OWASP-aligned review and pre-deployment gates before it ever reaches a tenant. There is no fast-lane for small changes.

Dedicated security team

Full-time, not a rotating responsibility. Owns the threat model, reviews every change, and signs off on every release that touches a tenant.

OWASP-aligned by default

OWASP Top 10 and OWASP ASVS Level 2 controls are the floor — not the ceiling. Every diff is audited against them, and the checklist evolves with every new OWASP advisory.

No change ships unreviewed

Single-line config tweak or a whole new module — the same automated scans and the same human security review apply. Size of change does not buy a shortcut.

Controls that gate every release

The platform layers automated enforcement and human review. Each control below runs on every commit, every PR, and every deployment — no exceptions, regardless of severity or scope.

OWASP-aligned code review on every PR

Every pull request — even a single-line change — is reviewed against OWASP Top 10 and OWASP ASVS controls by a member of the security team. There is no fast-lane that bypasses security review, no matter how small the diff.

Threat modeling before design freezes

New endpoints, new modules, and new external integrations go through a STRIDE-based threat-modeling session before implementation begins. Risks are identified, mitigations are designed in, and the threat model becomes part of the design record.

Automated security gates in CI

Every commit runs static application security testing (SAST), dependency vulnerability scanning, secret scanning, container image scanning, and infrastructure-as-code scanning. A failing gate blocks merge — exceptions require security-team sign-off and a tracked remediation date.

Signed supply chain, end to end

Application containers and module artifacts are cryptographically signed (RSA-4096) and verified at load time. Unsigned, tampered, or unexpected binaries cannot run in production — the host refuses to load them.

Independent penetration testing

Third-party penetration tests are commissioned on a recurring cadence by accredited firms. Findings are tracked in a remediation log the security team owns, and customer-visible summaries are available under NDA for enterprise tenants.

Coordinated disclosure & incident response

A published responsible-disclosure policy welcomes security researchers. Reports are triaged within one business day with severity-based remediation SLAs. Production incidents follow a documented playbook with customer-notification timelines and no-blame post-mortems that land back as code changes.

Encryption everywhere
TLS 1.2+ in transit with HSTS preload, AES-256 at rest for tenant data and credentials, no plaintext on any internal network hop.
Least privilege internally
Production access is role-gated, time-bound, and audited. Engineers do not hold standing production credentials.
SBOM per release
Every release ships with a software bill of materials so vulnerability disclosures can be triaged against your exact deployed version within hours, not days.
Continuous security training
Every engineer with code-merge rights completes annual secure-coding training. Refreshers follow every new OWASP Top 10 release.

Security is not a milestone we plan to hit later. It is the price of entry, and we pay it on every commit, every PR, and every deployment — even the boring ones.

Want to talk to our engineering team?

Architecture deep-dives, security questionnaires, performance characteristics, integration design — we are happy to go further than this page does.

Book an Architecture ReviewRead the Charter

Build smarter. Launch faster. Scale effortlessly.

Tell us where you want to take your business. We'll show you the fastest path to get there — whether you want a fully managed platform, a custom module built exclusively for your tenant, or a fully branded product to sell to your own clients.