Foundgine

HomeDocumentationReferenceADRs

Architecture Decision Records

Twelve foundational ADRs, recorded when the compile-time-first architecture was adopted. New ADRs are appended here — see Contributing → ADR Process before proposing one.

Contents


This document records the major architectural decisions that shape the Foundgine framework. It is intended to provide context for contributors and future maintainers, explaining not only what the architecture is, but why specific design choices were made.


ADR-001 — Compile-Time First Architecture

Status

Accepted

Context

Traditional GraphQL frameworks perform extensive runtime analysis using reflection, expression trees, and dynamic code generation. This increases startup time, memory usage, and complexity while limiting compatibility with Native AOT.

Decision

Foundgine moves as much work as possible from runtime to compile time using Roslyn Incremental Source Generators.

Compilation is responsible for:

Runtime executes precomputed artifacts.

Consequences

Advantages

Trade-offs


ADR-002 — Foundation Owns Contracts

Status

Accepted

Context

Runtime, SQL, GraphQL, and generated code require a common vocabulary.

Without a dedicated foundation layer, dependencies become cyclic and implementations leak across project boundaries.

Decision

Foundation defines:

Foundation references no other Foundgine project.

Consequences

Every project shares the same contracts while remaining loosely coupled.


ADR-003 — Runtime Depends on Interfaces

Status

Accepted

Context

The original Runtime directly referenced generated static classes such as:

GeneratedMetadata.GetEntity(...)

This tightly coupled Runtime to generated code.

Decision

Runtime depends on abstractions instead.

Example:

IMetadataProvider

implemented by:

GeneratedMetadataProvider

Consequences

Generated code becomes a plug-in rather than a dependency.

Runtime becomes reusable across transports.


ADR-004 — Immutable Metadata

Status

Accepted

Context

Runtime repeatedly consumes metadata.

Mutable metadata increases complexity and thread-safety concerns.

Decision

Every metadata object is immutable.

Examples include:

Metadata is created once and shared for the application’s lifetime.

Consequences


ADR-005 — Immutable Execution Plans

Status

Accepted

Context

Execution should not modify planning decisions.

Decision

QueryPlan and MutationPlan are immutable.

Planning performs analysis.

Runtime performs execution.

Consequences

Runtime becomes deterministic and easier to reason about.


ADR-006 — Generated Materializers

Status

Accepted

Context

Reflection-based materialization is slower and incompatible with Native AOT.

Decision

The Generator emits dedicated materializers for every model.

Runtime invokes generated materializers directly.

Consequences


ADR-007 — SQL Is a Serialization Layer

Status

Accepted

Context

Planning determines execution semantics.

SQL should not duplicate planning logic.

Decision

SQL converts immutable plans into dialect-specific SQL.

It performs no metadata discovery or semantic analysis.

Consequences

Clear separation between planning and serialization.


ADR-008 — GraphQL Is a Transport

Status

Accepted

Context

GraphQL frameworks often mix transport concerns with execution.

Decision

GraphQL only:

Execution occurs entirely within Runtime.

Consequences

The same Runtime can support GraphQL, gRPC, Web API, and future transports.


ADR-009 — Dependency Inversion for Generated Code

Status

Accepted

Context

Generated code should not dictate Runtime architecture.

Decision

Generated implementations satisfy Foundation interfaces.

Examples include:

Consequences

Generated code becomes replaceable and testable.


ADR-010 — Stable Identifier Allocation

Status

Accepted

Context

Changing identifier values unnecessarily creates noisy diffs and instability.

Decision

Identifiers are allocated deterministically after validation.

Allocation order should remain stable between builds unless the model changes.

Consequences

Cleaner generated code and more predictable version control history.


ADR-011 — Transport Independence

Status

Accepted

Context

Foundgine is intended to support multiple client technologies.

Decision

Runtime and SQL remain transport agnostic.

GraphQL, gRPC, and Web API become thin adapters over the same execution engine.

Consequences

New transports can be introduced without modifying Runtime.


ADR-012 — Native AOT Compatibility

Status

Accepted

Context

Native AOT imposes restrictions on reflection and runtime code generation.

Decision

Foundgine avoids:

Generated code replaces these mechanisms.

Consequences

Applications remain compatible with Native AOT while retaining high performance.


Summary

These architectural decisions establish the core principles of Foundgine:

Future architectural changes should be evaluated against these principles to preserve the framework’s long-term consistency and maintainability.



← Previous: Reference Next: FAQ