Common Patterns & Use Cases

Explore how ONDEMANDENV's core concepts are applied to solve common challenges and implement anti-stagnation patterns in managing distributed systems. Note that these patterns inherently involve secure cross-account interactions, orchestrated by the platform based on contracts defined in `contractsLib`.

Pattern: Isolated Full SDLC Environments per Service Branch

Problem: Traditional development often relies on a few shared, static environments (e.g., Dev, QA, Staging) which leads to contention, configuration drift, and deployment bottlenecks. Even modern containerized approaches using ephemeral namespaces often only provide isolated runtime environments, lacking the full context of infrastructure dependencies, versioned configurations, and cross-service interactions inherent in the complete SDLC. This forces rapid merging of small changes, hindering the development of complex features in true isolation.

ONDEMANDENV Solution: ONDEMANDENV promotes a shift towards isolated, full SDLC environments for each meaningful branch of a service. By cloning a stable base Enver (representing a complete Bounded Context), developers get a high-fidelity replica encompassing not just the service's code, but its specific infrastructure definition, versioned configuration, and resolved dependencies – essentially, an entire, independent lifecycle instance. This contrasts sharply with shared static environments or simple container/namespace isolation. It enables deep, meaningful branching strategies where complex features can be developed, deployed, and tested holistically over time within their own dedicated, consistent, and fully isolated SDLC environment, preventing conflicts and providing rapid, reliable feedback loops.

Conceptual Workflow:

  1. Developer Creates Feature Branch: A developer starts work on a new feature or bug fix by creating a new Git branch (e.g., `feature/new-auth-flow`) from a base branch (e.g., `dev`).
  2. Code & Commit with Clone Command: The developer makes code changes in their branch. When ready to test within its own lifecycle, they commit the changes including the special command odmd: create@dev (or the relevant base Enver branch name) in the commit message body.
  3. Platform Provisions Full SDLC Clone: ONDEMANDENV detects the command upon push. It automatically:
    • Creates a new dynamic Enver associated with the `feature/new-auth-flow` branch.
    • Resolves dependencies based on the state of the `dev` Enver (as specified in the command).
    • Deploys a full-stack SDLC clone (infrastructure, configuration, application) using the code from the `feature/new-auth-flow` branch into the designated target account/region, ensuring resource names are unique to this clone.
  4. Isolated SDLC Testing & Iteration: The developer receives the endpoint or access details for their dedicated clone Enver. They can perform integration tests, manual testing, or further iteration within their dedicated SDLC environment without impacting any other developer or shared environment.
  5. Merge & Delete Clone Environment: Once testing is complete and the feature is merged, the developer can trigger the clone environment's destruction by pushing an empty commit with odmd: delete in the message body on the feature branch. The platform cleans up all resources associated with the clone.

This pattern fundamentally changes the development dynamic, moving beyond shared bottlenecks and superficial ephemeral testing. It enables true parallel development of complex features within complete, isolated SDLC environments managed as code, allowing teams to innovate faster and more reliably.

Pattern: Managing Shared Networking Resources (VPC/TGW)

Problem: A dedicated networking team manages core infrastructure (VPCs, Transit Gateway, IPAM) in a central account. Application teams in separate workspace accounts need to consume these resources consistently and securely without managing the networking infrastructure themselves. Traditional tools like AWS CDK's `Cluster.addManifest` fail in this multi-account scenario because they assume single-account deployments and cannot resolve cross-account resource references.

ONDEMANDENV Solution: At first glance, using a shared resource seems to contradict the philosophy of complete isolation. However, ONDEMANDENV enables a pattern of governed sharing. The chaos of traditional shared environments comes from ungoverned, implicit dependencies. By defining the networking infrastructure as a platform Enver that publishes its capabilities as a formal `Product` within `contractsLib`, we eliminate the chaos. Application Envers consume this `Product` via an explicit, version-aware `Consumer` contract. This transforms the shared resource from a source of unpredictable risk into a stable, reliable platform service. It's no longer "sharing an environment and wishing for good luck"; it's sharing a contract-governed platform utility.

Network Architecture Overview

ONDEMANDENV solves multi-account networking through Transit Gateway as the network hub:

Why This Matters: CDK Limitations

AWS CDK's EKS implementation assumes single-account deployments, making it unsuitable for production multi-account architectures:

ONDEMANDENV's networking pattern addresses these limitations by providing runtime resolution of cross-account dependencies and establishing networking as a foundational platform service.

Implementation: Three Steps to Multi-Account Networking

1. Define Networking Platform Enver (`contractsLib`)

The networking team defines dedicated Envers for each isolated network (Production, Development):

// In MyOrgContracts.ts (contractsLib)
import { OdmdBuild, OdmdEnverCdk, Product } from '@ondemandenv/odmd-contracts-base';

const networkingBuild = new OdmdBuild(this, 'NetworkingBuild', {
    githubRepoAlias: 'networking-infra-repo',
    buildType: 'cdk',
});

// Production Network: 10.0.0.0/8 CIDR space
const networkingProd = new NetworkingPlatformEnver(this, 'NetworkingProd', {
    build: networkingBuild,
    targetAccountAlias: 'networking-prod-account',
    immutable: true,
    outputsProduct: new Product(this, 'Outputs'), // VPC IDs, TGW ID, NAT Gateway info
});

// Development Network: 172.16.0.0/12 CIDR space  
const networkingDev = new NetworkingPlatformEnver(this, 'NetworkingDev', {
    build: networkingBuild,
    targetAccountAlias: 'networking-dev-account',
    outputsProduct: new Product(this, 'Outputs'), // Separate network infrastructure
});

2. Implement Transit Gateway Network Infrastructure

The networking team's CDK stack creates the network foundation that spans multiple accounts:

// networking-infra-repo/lib/networking-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ipam from 'aws-cdk-lib/aws-ec2';
import { OdmdEnverCdk, OdmdShareOut } from '@ondemandenv/odmd-contracts-base';

export class NetworkingStack extends OdmdEnverCdk {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);

        // 🔗 Transit Gateway - The Network Hub
        const transitGateway = new ec2.CfnTransitGateway(this, 'TransitGateway', {
            amazonSideAsn: 64512,
            description: 'Hub for cross-account connectivity',
        });

        // 🌍 Shared NAT Gateway for Internet Access
        const natGateway = new ec2.NatGateway(this, 'SharedNatGateway', {
            // ... configuration ...
        });

        // 📊 IPAM for Centralized IP Management
        const ipamPool = new ec2.CfnIPAMPool(this, 'IpamPool', {
            ipamScopeId: 'ipam-scope-xxx',
            addressFamily: 'ipv4',
            provisionedCidrs: [{ cidr: '10.0.0.0/8' }], // Or 172.16.0.0/12 for dev
        });

        // 📦 Central VPC for Network Operations
        const centralVpc = new ec2.Vpc(this, 'CentralVpc', {
            cidr: '10.1.0.0/16', // Reserved for networking operations
            natGateways: 0, // Use shared NAT Gateway
        });

        // Attach Central VPC to Transit Gateway
        new ec2.CfnTransitGatewayVpcAttachment(this, 'CentralVpcAttachment', {
            transitGatewayId: transitGateway.ref,
            vpcId: centralVpc.vpcId,
            subnetIds: centralVpc.privateSubnets.map(s => s.subnetId),
        });

        // 🔄 Publish Network Infrastructure Details
        const networkOutputs = {
            transitGatewayId: transitGateway.ref,
            transitGatewayArn: `arn:aws:ec2:${this.region}:${this.account}:transit-gateway/${transitGateway.ref}`,
            ipamPoolId: ipamPool.ref,
            natGatewayId: natGateway.natGatewayId,
            centralVpcId: centralVpc.vpcId,
            // IP ranges for different platform accounts
            eksVpcCidr: '10.2.0.0/16',
            rdsVpcCidr: '10.3.0.0/16',
            appBaseCidr: '10.4.0.0/14', // 10.4-10.7 for app accounts
        };

        new OdmdShareOut(this, 'Outputs', { 
            value: cdk.Stack.of(this).toJsonString(networkOutputs) 
        });
    }
}

3. Platform Services Consume Network Infrastructure

Platform services (EKS, RDS) and application Envers connect to the shared network:

// In MyOrgContracts.ts (contractsLib)
import { OdmdBuild, Consumer, Product } from '@ondemandenv/odmd-contracts-base';

// EKS Platform Service connects to Production Network
const eksPlatformProd = new EksPlatformEnver(this, 'EksPlatformProd', {
    build: eksPlatformBuild,
    targetAccountAlias: 'eks-platform-account',
    outputsProduct: new Product(this, 'Outputs'), // EKS cluster details
    // Consume networking details to connect VPC to Transit Gateway
    networkingOutputsConsumer: new Consumer(this, 'NetworkingOutputs', networkingProd.outputsProduct),
});

// Application Enver connects to same network
const orderServiceProd = new OrderServiceEnver(this, 'OrderServiceProd', {
    build: orderServiceBuild,
    targetAccountAlias: 'order-service-account',
    outputsProduct: new Product(this, 'Outputs'), // Service endpoints
    // Consume networking for VPC connectivity
    networkingOutputsConsumer: new Consumer(this, 'NetworkingOutputs', networkingProd.outputsProduct),
    // Consume EKS platform details for deployment
    eksOutputsConsumer: new Consumer(this, 'EksOutputs', eksPlatformProd.outputsProduct),
});

Key Benefits vs. Traditional Approaches

This pattern provides several critical advantages:

The result: Applications inherit secure, managed connectivity without needing to understand the underlying multi-account network complexity—exactly what production-grade infrastructure requires.

Pattern: Deploying Applications to a Shared EKS Cluster

Problem: A platform team manages shared EKS clusters in a dedicated account (`workspace0` or `eks-account`). Application teams need to deploy workloads securely onto these clusters from their own workspace accounts, requiring cluster details, cross-account IAM permissions (IRSA), and manifest deployment capabilities.

ONDEMANDENV Solution: While some of our articles caution against choosing EKS for use cases where simpler alternatives exist, we recognize many organizations are already invested in Kubernetes. This pattern addresses that reality. It demonstrates how to integrate with a shared EKS cluster using a governed sharing model, mitigating the very complexity we warn about. Instead of ungoverned access, the EKS cluster becomes a platform Enver, publishing its capabilities as a formal `Product` in `contractsLib`. Application Envers consume this `Product` via an explicit, version-aware `Consumer` contract. This crucial step ensures the application's deployment is always bound to a specific, known version of the EKS platform, transforming a potentially chaotic shared resource into a stable, predictable utility.

1. Define EKS Platform Enver (`contractsLib`)

The platform team defines the EKS Enver, publishing necessary details within its single `Outputs` Product.

// In MyOrgContracts.ts (contractsLib)
import { OdmdBuild, OdmdEnverCdk, Product } from '@ondemandenv/odmd-contracts-base';
// Assuming EksPlatformEnver extends OdmdEnverCdk

const eksBuild = new OdmdBuild(this, 'EksBuild', { /* ... */ });

const sharedEksProd = new EksPlatformEnver(this, 'SharedEksProd', {
    build: eksBuild,
    targetAccountAlias: 'platform-workspace-account',
    immutable: true, // Assuming prod EKS is immutable
    // Products enabling cross-account deployment & IRSA are nested within Outputs
    outputsProduct: new Product(this, 'Outputs'), // Contains ClusterName, OidcArn, KubectlRoleArn etc.
});

2. Define Application Enver Consuming EKS Details (`contractsLib`)

The application team defines their Enver, consuming the `Outputs` Product from the EKS Enver.

// In MyOrgContracts.ts (contractsLib)
import { OdmdBuild, Consumer, Product } from '@ondemandenv/odmd-contracts-base';
// Assuming MyAppEksEnver extends OdmdEnverCdk
// Assuming myAppImgEnver is defined elsewhere and has an outputsProduct containing imageUri

const myAppBuild = new OdmdBuild(this, 'MyAppBuild', { /* ... CDK/cdk8s build ... */ });

const myAppEksDev = new MyAppEksEnver(this, 'MyAppEksDev', {
    build: myAppBuild,
    targetAccountAlias: 'app-dev-workspace-account',
    outputsProduct: new Product(this, 'Outputs'), // Its own outputs
    // Consume the single 'Outputs' product from the EKS Enver
    eksOutputsConsumer: new Consumer(this, 'EksOutputs', sharedEksProd.outputsProduct),
    // Consume image URI (potentially from another Enver's Outputs product)
    appImageOutputsConsumer: new Consumer(this, 'AppImageOutputs', myAppImgEnver.outputsProduct),
});

3. Implement Application CDK Stack (IAM + k8s Manifests)

The application's CDK stack consumes the EKS outputs JSON, parses it, defines the app-specific IAM role, and the Kubernetes manifests.

// Simplified example in my-app-repo/lib/app-eks-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as cdk8s from 'cdk8s';
import { OdmdEnverCdk } from '@ondemandenv/odmd-contracts-base';

// Interfaces for parsed outputs
interface EksOutputs { clusterOidcArn: string; /* ... other fields ... */ }
interface AppImageOutputs { imageUri: string; /* ... */ }

export class MyAppEksStack extends OdmdEnverCdk {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    // --- Consume and Parse shared values ---
    const eksOutputsJson = OdmdEnverCdk.getSharedValue('EksOutputs');
    const appImageOutputsJson = OdmdEnverCdk.getSharedValue('AppImageOutputs');
    const eksOutputs: EksOutputs = JSON.parse(eksOutputsJson || '{}');
    const appImageOutputs: AppImageOutputs = JSON.parse(appImageOutputsJson || '{}');

    // --- Define App-Specific IAM Role (IRSA) in App Account ---
    const podRole = new iam.Role(this, 'PodRole', {
        // Trust policy uses OIDC ARN parsed from consumed EKS Outputs
        assumedBy: new iam.FederatedPrincipal(eksOutputs.clusterOidcArn, { /* ... conditions ... */ }, 'sts:AssumeRoleWithWebIdentity'),
    });
    // Grant permissions to podRole as needed

    // --- Define Kubernetes Manifests using cdk8s ---
    const app = new cdk8s.App();
    const chart = new cdk8s.Chart(app, 'MyAppChart');
    // ... Define Deployment (using appImageOutputs.imageUri), ServiceAccount (annotated with podRole.roleArn) ...

    // Platform deployment logic implicitly uses the KubectlRoleArn (parsed from EksOutputs)
    // to assume role in the EKS cluster account and apply these manifests.
    // Note: OdmdShareOut for this stack's outputs is omitted for brevity
  }
}

ONDEMANDENV orchestrates the cross-account deployment securely, ensuring the application team manages their IAM and K8s configurations together within their Enver.

Pattern: Enabling Advanced Deployments (Blue/Green, A/B)

Problem: Implementing Blue/Green or A/B testing often involves duplicating configurations, managing complex traffic shifting logic, and ensuring consistency across potentially different accounts or infrastructure variants.

ONDEMANDENV Solution: Leverage distinct Envers for each application version and a dedicated Routing/Traffic Management Enver to control user traffic flow.

  • Application Versions as Envers:
    • Blue/Green: Maintain two distinct, stable Envers (e.g., `myApp-blue` and `myApp-green`), potentially targeting different accounts or the same one. Each publishes its unique endpoint URL or service identifier as a `Product`.
    • A/B Testing / Experimentation: Create `Clones` of a base Enver or define distinct feature Envers. Each variant publishes its endpoint `Product`.
  • Dedicated Routing Enver: Create a separate Enver specifically to manage traffic distribution. This Enver would:
    • `Consume` the endpoint `Products` published by the relevant application Envers (e.g., blue endpoint, green endpoint, variant A endpoint, variant B endpoint).
    • Control the traffic shifting mechanism, such as:
      • Updating weighted DNS records (e.g., Route 53 CNAME weights).
      • Configuring API Gateway stages or routes.
      • Modifying Load Balancer target group weights or listener rules.
    • Deployments to this Routing Enver directly control the user traffic percentage split or cutover between application versions.
This separation ensures the application deployment lifecycle (managed by app Envers) is decoupled from the traffic routing lifecycle (managed by the Routing Enver). Because Envers manage their respective stacks consistently, even across accounts, creating and managing these multiple versions and controlling traffic flow becomes significantly more reliable and manageable. The platform handles the underlying cross-account complexity for both application deployments and routing configurations based on the definitions in `contractsLib`.

Pattern: AI-Assisted Development within Bounded Contexts

Problem: AI code generation tools, while powerful, often produce code that violates architectural boundaries, introduces tight coupling, or creates accidental complexity. Without proper constraints and context, AI can generate technically correct but architecturally problematic solutions that compromise long-term maintainability and system coherence. Traditional development approaches lack the structured contracts and boundaries needed to guide AI toward producing well-architected, Domain-Driven Design-compliant code.

ONDEMANDENV Solution: ONDEMANDENV provides the perfect framework for AI-assisted development by establishing clear bounded contexts, explicit contracts, and isolated testing environments. The platform's `contractsLib` serves as a specification that AI can reference to generate code that respects domain boundaries, uses correct interfaces, and integrates properly with the existing system. This approach transforms AI from a potential source of accidental complexity into a powerful tool for generating maintainable, DDD-compliant code.

AI-Guided Development Workflow:

  1. Define Bounded Context in contractsLib: Establish clear boundaries, responsibilities, and contracts for your domain before involving AI in code generation.
  2. Provide AI with Architectural Context: Share the relevant `BuildDefinition`, `Enver` definitions, and `Product`/`Consumer` contracts with your AI assistant to establish architectural constraints.
  3. Generate Code within Boundaries: Request AI to generate code that operates within the defined bounded context, referencing specific contracts and dependency interfaces.
  4. Validate in Isolated Environment: Use ONDEMANDENV's cloning capability to create an ephemeral environment for testing AI-generated code without affecting shared infrastructure.
  5. Iterate with Contract Evolution: If AI suggests interface changes, evolve contracts through the proper governance process in `contractsLib` before implementing.

Example: AI-Assisted Microservice Development

Consider developing a new authentication service using AI assistance within ONDEMANDENV:

1. Define the Bounded Context (`contractsLib`)

// In MyOrgContracts.ts
const authServiceBuild = new OdmdBuild(this, 'AuthServiceBuild', {
    githubRepoAlias: 'auth-service-repo',
    buildType: 'cdk',
});

const authServiceDev = new AuthServiceEnver(this, 'AuthServiceDev', {
    build: authServiceBuild,
    targetAccountAlias: 'dev-workspace-account',
    // Define what this service will provide
    outputsProduct: new Product(this, 'Outputs'), // JWT endpoints, user validation APIs
    // Define dependencies it needs
    userDbConsumer: new Consumer(this, 'UserDbOutputs', userDbEnver.outputsProduct),
    auditLogConsumer: new Consumer(this, 'AuditLogOutputs', auditLogEnver.outputsProduct),
});

2. AI Code Generation with Architectural Context

Provide your AI assistant with the contract definition and request code generation:

// AI Prompt: "Generate a CDK stack for the AuthServiceEnver that:
// 1. Consumes UserDb outputs for user data access
// 2. Consumes AuditLog outputs for security logging  
// 3. Publishes JWT endpoint and validation API as outputs
// 4. Follows Application-Centric Infrastructure principles
// 5. Uses the consumed database connection for user authentication"

export class AuthServiceStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props: cdk.StackProps) {
        super(scope, id, props);
        
        // AI-generated code respects contract boundaries
        const userDbConfig = JSON.parse(OdmdEnverCdk.getSharedValue('UserDbOutputs') || '{}');
        const auditConfig = JSON.parse(OdmdEnverCdk.getSharedValue('AuditLogOutputs') || '{}');
        
        // AI generates infrastructure within bounded context
        const authLambda = new lambda.Function(this, 'AuthFunction', {
            // ... AI-generated Lambda configuration
            environment: {
                USER_DB_ENDPOINT: userDbConfig.endpoint,
                AUDIT_LOG_TOPIC: auditConfig.topicArn,
            }
        });
        
        // AI publishes outputs according to contract
        new OdmdShareOut(this, 'Outputs', {
            value: cdk.Stack.of(this).toJsonString({
                jwtEndpoint: authApi.url,
                validationEndpoint: `${authApi.url}/validate`,
            })
        });
    }
}

3. Isolated Testing with Cloning

Test the AI-generated code in isolation:

git commit -m "feat: AI-generated auth service implementation

odmd: create@AuthServiceDev"

This creates a temporary environment where the AI-generated authentication service can be tested without affecting other services or shared infrastructure.

4. Contract Evolution and Governance

If AI suggests adding new outputs or changing interfaces, update `contractsLib` through proper governance:

// AI suggests adding password reset capability
// Update contract in contractsLib through PR process
const authServiceDev = new AuthServiceEnver(this, 'AuthServiceDev', {
    // ... existing configuration
    outputsProduct: new Product(this, 'Outputs'), // Now includes password reset endpoints
    // AI identifies need for email service
    emailServiceConsumer: new Consumer(this, 'EmailServiceOutputs', emailServiceEnver.outputsProduct),
});

Benefits of AI + ONDEMANDENV + DDD

This pattern demonstrates how ONDEMANDENV transforms AI from a potential source of technical debt into a powerful ally for building maintainable, well-architected systems that follow Domain-Driven Design principles.