Skip to content
NorseArchitecturePublic

About

The realm of the Æsir, whose laws bind gods and mortals alike. Norse.Abstractions.* — the interfaces, contracts, and marker types every realm must honor to live and operate on the Norse platform. Implementations are forged in Svartalfheim; the laws are written here.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Asgard

The fortress of the Æsir, where law is declared and the cosmos answers to it.

Asgard — the golden fortress of the Æsir, where the gods hold council and the laws that govern all nine realms are declared

Image credit: @norsemythologyclips — go follow them.

Declared law for the Norse Architecture — Norse.Abstractions: the contracts and rules every realm must honor. No implementations live here, by design. Seven assemblies plus two source generators, split by dependency wall and consumer context:

Assembly Upstream Purpose
Norse.Abstractions.Contracts Norse.Primitives Outcome<T> with Problem/ErrorCategory/BoolResponse/Unit, and ErasureReceipt; Problem.Code/Problem.NextUrl (a machine-readable refinement and an advisory server-authored next hop) with NorseErrorCodes (reauthentication-required)
Norse.Abstractions.Components Abstractions.Contracts, ASP.NET Core Components Razor component base abstractions (AsyncComponentBase, IAppShellLayout, IDashboardWidget) plus the outcome-form seam hoisted from Heimdall (OutcomeFormComponentBase — forms submit only when interactive (a statically rendered submit never dispatches; bind Disabled="!CanSubmit") — and the ServerValidation/ bridge) — MAUI/WASM-safe, no server-side types; the non-form outcome dispatch sibling OutcomeComponentBase (click triggers bind Disabled="!CanAct" — interactive and not dispatching; loaders are not gated); both bases soft-navigate a reauthentication-required refusal to its NextUrl when LocalNavigation passes it, and render every other failure; and the authorization vocabulary — policy names (NorsePolicies, including RecentAuthentication), lanes (NorseLanes), audiences (NorseAudiences), auth_time (NorseClaimTypes) and the policy helpers (NorseLanePolicyExtensions: RequireLane, AllowAnyLane, RequireAudience, CloseLaneByDefault)
Norse.Abstractions.Backend .Contracts The read contract (IReadRepository<TView>, IViewBearer<TView>), the serialization seam, and the key custody seam
Norse.Abstractions.Web.Server .Backend, FluentValidation The mediator law (IRequest/ICommandRequest/IQueryRequest, ISender, IRequestHandler, IBehavior, CommandRequest, CommandRequestValidator), ReauthenticationLandingAttribute (the local page a request lands back on after reauthentication), the gRPC facade (GrpcControllerBase, ProblemErrorEntry), and IDeferredSignIn
Norse.Abstractions.Worker .Backend Declared and deliberately empty — worker-side contracts land with their first consumer
Norse.Abstractions.Migrations none IMigrationContributor and ISeedContributor (EF-free)
Norse.Abstractions.Emit none The generator-authoring toolkit (CSharpEmit, Utf8NoBom) — netstandard2.0 so source generators across the platform can consume it
Abstractions.Web.Server.Generator .Emit HandlerRegistrationGenerator — compile-time handler/dispatch/validator registration (AddNorse{Realm}Handlers()), bundled inside the Norse.Abstractions.Web.Server package
Abstractions.Policy.Analyzers none NorsePolicyDeclarationAnalyzer (NORSE015) — validates [NorsePolicy] declarations at the source that authors them, bundled inside the Norse.Abstractions.Components package

Worker and Web.Server are mutually invisible — neither references the other.

The dependency graph

Arrows point at the thing depended on. The isolated nodes are deliberate: Migrations and Emit ride on nothing so anything can ride on them, and Components touches only the Razor framework so it compiles into WASM and MAUI unburdened.

flowchart BT
	subgraph Asgard["Asgard — Norse.Abstractions"]
		Contracts
		Components
		Backend
		WebServer["Web.Server"]
		Worker
		Migrations
		Emit
		Generator["Web.Server.Generator (gen)"]
	end
	subgraph Svartalfheim["Svartálfheim"]
		Primitives["Norse.Primitives"]
	end
	Contracts --> Primitives
	Backend --> Contracts
	WebServer --> Backend
	Worker --> Backend
	Generator --> Emit
	Generator -.->|"bundled analyzer inside the Web.Server package"| WebServer
Loading

The law in force

  • Outcome<T> — the platform's second discriminated union and the interior half of the two unions: it faces operations inside the host and describes an event — "this operation ran; here is how it went" — where Svartálfheim's Result<T> faces the boundary and describes data. A hand-rolled sealed class union, [MustConsume]-decorated, deliberately starved API (Ok/Err/Match — no typed happy-path accessors, so the unhappy path cannot be politely glanced past). It is never serialized, stored, or compared; each transport edge translates it into its native tongue. Live today: Blazor components consume Task<Outcome<T>> from the gRPC service contracts and pattern-match the result.
  • The mediator law is server-only, deliberately — the marker family lives in Web.Server so wire records shipped to WASM stay pure [DataContract] shapes with zero mediator coupling. Realms give a wire DTO server-side identity by deriving CommandRequest<TRequest,TResponse>, and the same client-side FluentValidation class runs again on the server through CommandRequestValidator.
  • The registration generator rides the contract package — it discovers a realm's IRequestHandler/IValidator implementations at compile time and emits DI registration, replacing assembly scanning. It lives here (not in the infrastructure realm) because handler-bearing realms may legally depend only on declared law; duplicate handlers and requests without an [Authorize] policy are build errors (NORSE010/NORSE011).
  • A lane is the kind of credential, and every policy is closed by default — NorseLanes names the three ways in: Identity (the browser's cookie), User (a user bearer token from the authorization code flow) and Machine (a machine token from client credentials, for the REST façade). Midgard stamps the lane itself, admits a bearer into a lane only when its audience matches that kind of token, and closes every declared policy that names no lane to Identity alone (CloseLaneByDefault); AllowAnyLane() is the explicit, greppable opt-out. A bearer-admitting policy names its lane with RequireLane and pins its audience with RequireAudience. NorsePolicies.Machine now means exactly that: the Machine lane plus the Facade audience — never a cookie, never a user bearer.
  • Freshness stacks on an operation's own policy — NorsePolicies.RecentAuthentication checks auth_time against the configured window and never narrows the lanes. A stale caller is refused as Forbidden + reauthentication-required, with a server-authored NextUrl to sign in again and land back on the request's [ReauthenticationLanding] page; the component bases take that hop only when the URL is local.
  • IMigrationContributor — the thinnest contract in the platform, live on NuGet, and the seed behind the migrations framework proven end to end across six realms (the full story is on Bifröst's README). No Order, no DependsOn: sequencing between contributors would couple bounded contexts.

Egress contracts (Norse.Abstractions.Backend.Egress) are staged, not yet executed. Every new surface follows the spec-first discipline: brainstorm → spec → plan in Glitnir's docs/Asgard/, greenlit by the human, then code.

Build and test

dotnet build Asgard.slnx   # warnings are errors — a single warning fails
dotnet test Asgard.slnx    # xUnit v3 + Shouldly on Microsoft.Testing.Platform

Requires the .NET 11 preview SDK pinned by global.json. The realm builds standalone — it is its own clone target, not only a Bifröst submodule.

The naming law

Project folders and .csproj files are brand-free (src/Abstractions.Contracts/Abstractions.Contracts.csproj); the realm's root Directory.Build.props injects AssemblyName and RootNamespace as Norse.$(MSBuildProjectName). Fork it, change Norse once, and every build output carries your brand — the namespace Norse.* declarations in code are yours to cull deliberately, with no filesystem change either way.

The cosmos

Asgard is one realm of the Norse Architecture. The whole platform composes at Bifröst — clone once, cross the bridge. Every design is tried in Glitnir, the design court, before law is declared here; this realm's specs and plans live in the court's docs/Asgard/.

Soundtrack: Twilight of the Thunder God

Soundtrack: Twilight of the Thunder God

About

The realm of the Æsir, whose laws bind gods and mortals alike. Norse.Abstractions.* — the interfaces, contracts, and marker types every realm must honor to live and operate on the Norse platform. Implementations are forged in Svartalfheim; the laws are written here.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages