Core Concepts of ONDEMANDENV
ONDEMANDENV introduces several core concepts designed to bring order, consistency, and agility to the management of complex distributed systems. Understanding these concepts is key to leveraging the platform's power. For a deeper technical overview, see the ONDEMANDENV Architecture Deep Dive article.
Note on Implementation: While the current examples and reference implementation heavily utilize AWS CDK and CloudFormation for defining and deploying resources, the core ONDEMANDENV principles – Application-Centricity, Envers, contractsLib, Cloning, and Platform Abstraction – are tool-agnostic. The same conceptual framework could be implemented using other Infrastructure-as-Code tools like Terraform CDK, Pulumi, or potentially even primarily with cdk8s for environments heavily focused on Kubernetes orchestration. The key is the pattern of codified contracts, versioned environments, and platform automation.
Application-Centric Infrastructure
Instead of viewing infrastructure and applications as separate entities managed by different tools (like CloudFormation for infra, Kubernetes/Helm for runtime), ONDEMANDENV adopts an Application-Centric approach.
- Vertical Slice as Unit: A modern "application" is treated as a complete vertical slice of business functionality. This includes not just containers, but also databases (RDS, DynamoDB), storage (S3), networking (VPCs, Load Balancers), serverless functions (Lambda), API Gateways, and crucially, the associated security posture (IAM Roles, Policies).
- Bounded Context: This entire vertical slice is managed as a single, cohesive unit, mirroring the concept of a "Bounded Context" from Domain-Driven Design (DDD). Resources are grouped logically by their relationship to the business capability, not just their physical type.
- Unified Management: Leveraging tools like AWS CDK allows defining both infrastructure and runtime components (including Kubernetes manifests via cdk8s) within a single codebase and toolchain. This reduces fragmentation and toolchain sprawl.
- Benefits: This approach leads to improved consistency, enhanced manageability (atomic deployments/rollbacks), clear ownership, better cost attribution, and a stronger security posture through embedded least-privilege principles.
Crucially, the scope defined by an Application-Centric approach (and therefore the scope of a BuildDefinition
and its Envers
) is subjective and user-determined, guided by Domain-Driven Design principles. It can range from a single deployable artifact like a container image or shared library package, to a specific frontend deployment, a full-stack vertical slice, or even complex platform infrastructure like a dedicated EKS cluster Enver.
AI-Assisted Development Benefits: This Application-Centric model provides the architectural structure that AI tools need to generate maintainable code. By establishing clear bounded contexts and explicit contracts, AI can generate code that respects domain boundaries, uses proper interfaces, and integrates correctly with existing systems. Rather than producing monolithic or tightly-coupled solutions, AI working within ONDEMANDENV's constraints naturally produces code aligned with Domain-Driven Design principles, preventing the "accidental complexity" often introduced by unconstrained AI code generation.
Enver (Environment Version)
An Enver represents a specific, deployable composite version of an application's Bounded Context, as defined by a BuildDefinition
in `contractsLib`. It acts as a holistic, logical environment managed as an atomic unit. Its version encompasses both its source code commit and the exact versions of all dependency Products it consumes.
- Instance of a Build: Each Enver definition in `contractsLib` is an instance of a specific
BuildDefinition
, representing one particular version (tied to a Git branch or tag) deployed to a specific target environment (AWS Account/Region). - Composite Versioning via Git & Dependencies: Envers link environment state directly to versioned dependencies:
- Branch Envers (Incremental Composite Versions): Associated with a Git branch. These represent evolving versions that can change due to:
- New code commits pushed to the Enver's source branch (defined in the `BuildDefinition`).
- Updates to the `Products` consumed from dependency Envers (which may themselves be Branch Envers).
- Tag Envers (Immutable Composite Versions): Associated with a Git tag. These represent fixed, point-in-time versions where both the source code and all consumed dependency versions are locked. This is enforced by the rule that Tag Envers can only declare dependencies on (`Consume`) `Products` published by other Tag Envers. This creates a fully immutable dependency chain, guaranteeing absolute reproducibility. Ideal for staging, production releases, or critical point-in-time validation.
- Branch Envers (Incremental Composite Versions): Associated with a Git branch. These represent evolving versions that can change due to:
- Holistic Definition: An Enver encapsulates everything needed for its specific composite version – the infrastructure (defined via CDK based on its source code version), configuration values (including resolved consumed Product versions), references to code artifacts (like Docker image URIs), dependency declarations (`Consumers`), and the target AWS account/region for deployment.
- Atomic Deployment Unit: Each Enver (representing a specific composite version of a BuildDefinition) is deployed and rolled back as a single transaction (leveraging CloudFormation). This ensures the infrastructure, runtime configuration, and application components are always consistent with that specific composite version.
- Versioned Config Store: The underlying config store (e.g., AWS SSM Parameter Store) naturally versions the `Product` values published by Envers, enabling the platform to resolve and track the specific dependency versions consumed by each Enver deployment.
- Isolation: Different Enver versions (whether branch or tag based) of the same BuildDefinition are logically isolated.
- Parameterization for Consistency: CDK code uses the Enver's identifier (branch/tag) to parameterize resources, maintaining functional consistency across different versions.
Contracts Library (`contractsLib`)
The contractsLib is a dedicated, version-controlled repository (typically TypeScript) that serves as the central declaration hub and single source of truth for your entire distributed system\'s architecture and dependencies. It focuses solely on the contracts and boundaries between different services (Bounded Contexts) and teams, not their internal implementation details. This repository is the source that gets packaged (e.g., via npm pack) and provided to the platform during the initial setup process.
- Architecture as Code (Declarations): Defines service boundaries (mapping to Bounded Contexts via
BuildDefinition
s), environment instances (Enver
definitions), inter-service dependencies (Products
andConsumers
), and organizational mappings (target AWS accounts, source GitHub repos). It declares what services exist, where their code lives, what they produce/consume, and where their different versions (Envers) should be deployed. - Dependency Management: Explicitly defines which `Products` (outputs like ARNs, URIs, configuration values) an Enver publishes and which Products other Envers `Consume` (inputs). The platform uses this graph to orchestrate deployments and manage dependencies effectively.
- Eliminating Ambiguity: If a dependency or configuration isn't defined in `contractsLib`, it effectively doesn't exist for the platform. This forces clarity and explicit agreement on service interactions.
- Governance ("Congress"): Changes to `contractsLib` (declarations, contracts, dependencies) are managed via standard code review processes (Pull Requests). This acts as a governance mechanism where teams negotiate and agree upon architectural changes and inter-service contracts before they are implemented.
- AI Code Generation Guidance: The explicit contracts and bounded contexts defined in `contractsLib` serve as precise specifications that AI tools can reference when generating code. This ensures AI-generated solutions respect architectural boundaries, use correct interfaces, and maintain system coherence. The contracts provide the context AI needs to produce maintainable, well-architected code rather than ad-hoc solutions.
- Platform Integration: The ONDEMANDENV platform monitors `contractsLib`. Changes trigger updates to the central configuration store and downstream deployment pipelines (defined in the implementation repos) for affected Envers.
- Typing and Validation: Uses TypeScript for strong typing. The core platform provides base interfaces and classes in a foundational package like
ondemandenv/odmd-contracts-base
. User-definedcontractsLib
repositories, such as the exampleondemandenv/odmd-contracts-sandbox
, extend these base contracts. This layered approach is crucial:odmd-contracts-base
defines standard contract structures, for instance, for how a console application should interface with the platform's central services (e.g., for authentication or data queries via AWS AppSync). An example isodmd-build-user-auth.ts
.- An implementation like
odmd-contracts-sandbox
(e.g., inOdmdBuildUserAuthSbx.ts
) then extends these base contracts to bridge a specific user console implementation with the platform. - This allows a project like
ondemandenv/user-pool
to use its chosen authentication mechanism (e.g., Amazon Cognito) to manage console user access. The contracts ensure that the console can correctly authenticate users and authorize them to assume the necessary IAM roles for accessing configuration or parameter store data, as governed by the ONDEMANDENV platform.
contractsLib
can further guarantee its integrity (e.g., preventing immutable Envers from depending on incremental ones).
Within `contractsLib`, these concepts define the Bounded Contexts and how they interact.
-
OdmdBuild<T extends OdmdEnver>
: Represents the build configuration for a specific type of Enver (e.g., `OdmdBuild`). Defined in `contractsLib`, it associates the Enver type with its source code and build process: - Typically configured with the source code repository alias (githubRepoAlias), the build type (buildType: 'cdk', 'docker', 'cmd'), and optionally source paths or commands.
- This construct defines how to build a specific *type* of Enver from a given source.
-
OdmdEnverCdk | OdmdEnverCmd | OdmdEnverDocker
(or custom subclasses): Represents a specific, deployable instance or version of a service/component, tied to a Git branch/tag and a target environment. Defined in `contractsLib` using its specific class:- Linked to its corresponding
OdmdBuild
instance. - Specifies deployment target (
targetAccountAlias
,targetRegion
). - Holds the declarations for
Product
(s) it publishes andConsumer
(s) for dependencies it requires. - Marked as
immutable: true
for Tag Envers.
- Linked to its corresponding
- Product: (Conventionally named 'Outputs') A single, named output value (typically a JSON string containing multiple outputs) that an Enver makes available. Declared in `contractsLib` as part of an Enver definition (e.g.,
outputsProduct: new Product(this, 'Outputs')
). Represents the public interface of that specific Enver instance. - Consumer: A declaration within an Enver definition in `contractsLib` stating its requirement for the
Outputs
Product from another Enver (e.g.,new Consumer(this, 'LocalConsumerName', otherEnver.outputsProduct, '{...defaultJson...}')
). The platform resolves this dependency, providing the consuming Enver's implementation code with the concrete JSON string value of the dependency's published Outputs. Default values can be provided.
This explicit structure defines the architecture and dependencies, linking specific Enver instances (like `OrderManagerDev`) to their build sources (`OdmdBuild
On-Demand Cloning (Dynamic/Ephemeral Envers)
A key feature enabling developer agility is the ability to create dynamic, ephemeral clones of the static Envers declared in contractsLib
.
- Cloning Static Branch Envers: Developers typically clone a static Branch Enver (e.g., the one associated with the `dev` or `main` branch) defined in `contractsLib`. This creates a new, temporary, dynamic Enver linked to the developer's feature branch.
- Dynamic Lifecycle (Ephemeral): These cloned Envers are intended to be short-lived (ephemeral). They are created and destroyed dynamically via simple Git commit comments, typically:
odmd: create@<source_branch_enver_id>
(e.g.,odmd: create@MyServiceDev
): Creates the clone, linked to the commit's feature branch.odmd: delete
: Destroys the clone associated with the commit's feature branch.
- Dependency Reuse: A cloned (dynamic) Enver reuses the exact same resolved dependency Product versions as its source static Enver had at the time the clone command was processed. This ensures the clone operates within a consistent and predictable dependency context based on its origin.
- Resource Isolation: While dependency versions are inherited, the platform ensures that the actual infrastructure resources deployed by the clone itself (using its feature branch code) are uniquely named and isolated from the source static Enver and other clones, preventing conflicts.
- Static Envers Remain Unchanged: Cloning operations *do not affect* the original static Envers declared in `contractsLib`. Those Envers remain consistent with their definition and continue their own lifecycle based on commits to their associated branch/tag.
- Use Cases: Perfect for feature development, bug fixing, safe experimentation, CI validation of PRs, performance testing, or running temporary E2E tests without impacting shared static environments or risking dependency conflicts.
- AI Development Support: Cloning provides an ideal environment for testing AI-generated code. Developers can rapidly experiment with AI-suggested implementations in isolated environments, validate architectural compliance, and iterate on solutions without affecting other team members or stable environments.
Cloning provides developers with nearly instant access to isolated, full-stack, high-fidelity environments based on a known good static baseline, greatly accelerating testing and iteration cycles.
Platform Abstraction: Enabling Unified Control
A core goal of ONDEMANDENV is to abstract away underlying infrastructure and system interaction complexity, allowing developers to define and control their entire Application-Centric Bounded Context via their Enver, regardless of where resources physically reside.
- Unified Resource Ownership Across Boundaries: The platform provides the mechanisms to make the Application-Centric approach practical, even across AWS accounts, GitHub, or potentially other clouds. It handles the complex authentication, authorization, and interaction logic required for an Enver's deployment process (e.g., its CDK code or associated scripts) to manage all resources logically belonging to its Bounded Context. This includes:
- Assuming the correct cross-account IAM roles for deploying AWS resources (defined via `contractsLib` targets).
- Authenticating as the organization's GitHub App (using the centrally stored private key) to manage workflows, checks, or repository settings defined within an Enver.
- Executing `kubectl` commands against shared EKS clusters in other accounts (using appropriate consumed roles/endpoints).
- Potentially orchestrating deployments to other cloud platforms (e.g., GCP GKE via custom CDK resources) using centrally managed credentials and platform logic.
- Platform Services via Standard Contracts: Common infrastructure components (Networking, EKS, CI/CD runners, Monitoring Agents, etc.) can be provided as standardized "Platform Envers". Application teams consume these foundational services via the normal Product/Consumer mechanism in `contractsLib`, simplifying access to complex shared resources without needing deep operational expertise for those specific domains.
- Automated Workflows & Dependency Management: Beyond resource deployment, the platform automates critical background tasks such as dependency resolution (fetching the correct versioned Product values from the config store based on `contractsLib` definitions), event handling based on Product changes (triggering downstream Enver pipelines), and managing access to secrets, further reducing the operational burden on application teams.
By abstracting the complexities of cross-boundary interactions and infrastructure management, ONDEMANDENV empowers developers to focus on their core domain logic while maintaining true, unified ownership over their entire application slice, wherever its components may run.