This commit is contained in:
Tiara Rodney 2026-02-05 01:51:29 +01:00
commit 41481636d8
No known key found for this signature in database
GPG key ID: 5CD8EC1D46106723
12 changed files with 2126 additions and 0 deletions

378
profiles/cdk-ts.md Normal file
View file

@ -0,0 +1,378 @@
# CDK TypeScript Profile
## Concept → CDK Mapping
| ABC Concept | Meaning | CDK Mapping |
|---------------|-------------------------|-----------------------------------------|
| ABCC0 | Construct | `Construct` subclass |
| ABCC1 | Application Stack | `Stack` subclass |
| ABCC2 | Logical Unit (LU) | `Construct` subclass with LU semantics |
| ABCC3 | Resource Group (RG) | `Construct` subclass with RG semantics |
| ABCC4 | Input Contract | TypeScript interface (`InputContract`) |
| ABCC5 | Output Contract | TypeScript interface (`OutputContract`) |
| ABCC6 | Instantiation Interface | Constructor (`scope`, `id`, `inputs`) |
| ABCC7 | Capturing Down | Passing inputs to children |
| ABCC8 | Bubbling Up | Exposing outputs upward |
*ABC* itself remains namingagnostic; this profile defines CDKidiomatic
conventions.
## Rules
These are profilespecific rules for CDK-Typescript users.
### ABC-PROFILE-CDKTSR1 (SHOULD)
The directory structure SHOULD reflect the ABC hierarchy:
Application Stack → Logical Units → Resource Groups.
### ABC-PROFILE-CDKTSR2 (SHOULD)
Each Logical Unit SHOULD reside in its own toplevel directory:
```default
src/
app-stack.ts
data/
logic/
presentation/
```
### ABC-PROFILE-CDKTSR3 (SHOULD)
Each Resource Group SHOULD reside inside its parent Logical Unit:
```default
src/data/storage/
src/data/database/
```
### ABC-PROFILE-CDKTSR4 (SHOULD)
Each construct directory SHOULD contain an index.ts exporting the construct.
### ABC-PROFILE-CDKTSR5 (SHOULD)
File and directory names SHOULD follow CDK naming conventions.
### ABC-PROFILE-CDKTSR6 (MAY)
Modules MAY split into multiple files if needed, as long as they remain in the
same directory.
### ABC-PROFILE-CDKTSR7 (SHOULD)
Each construct module SHOULD define its own `InputContract` and
`OutputContract`.
### ABC-PROFILE-CDKTSR8 (SHOULD)
Within a module, contracts SHOULD be named simply `InputContract` and
`OutputContract`.
### ABC-PROFILE-CDKTSR9 (SHOULD)
When importing contracts from another module, they SHOULD be aliased:
### ABC-PROFILE-CDKTSR10 (MUST)
Constructs MUST be instantiated using a single InputContract object.
Also see ABCR30/32.
### ABC-PROFILE-CDKTSR11 (MUST)
All crossconstruct wiring MUST occur in the parent construct.
Also see ABCR44.
### ABC-PROFILE-CDKTSR12 (SHOULD)
Imported contracts SHOULD be aliased to descriptive names.
### ABC-PROFILE-CDKTSR13 (SHOULD)
Contracts SHOULD be colocated with their construct modules.
### ABC-PROFILE-CDKTSR14 (SHOULD)
Generated code SHOULD mirror the ABC hierarchy in structure and composition.
### ABC-PROFILE-CDKTSR15 (SHOULD)
Construct internals SHOULD NOT be accessed except through outputs.
### ABC-PROFILE-CDKTSR16 (SHOULD)
Constructs SHOULD be generated in ABC order: Resource Groups → Logical Units →
Application Stack.
## Base ABC Classes for Typescript-CDK
### Core Types
```javascript
export interface InputContract {}
export interface OutputContract {}
export interface HasOutputs<TOutputs extends OutputContract> {
readonly outputs: TOutputs;
}
```
### Application Stack Base
```javascript
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { OutputContract } from './core-types';
export abstract class ABCApplicationStack<
TOutputs extends OutputContract = OutputContract
> extends Stack {
public abstract readonly outputs: TOutputs;
protected constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
}
}
```
### Logical Unit Base
```javascript
import { Construct } from 'constructs';
import { InputContract, OutputContract, HasOutputs } from './core-types';
export abstract class ABCLogicalUnit<
TInputs extends InputContract,
TOutputs extends OutputContract
> extends Construct implements HasOutputs<TOutputs> {
public abstract readonly outputs: TOutputs;
protected readonly inputs: TInputs;
protected constructor(scope: Construct, id: string, inputs: TInputs) {
super(scope, id);
this.inputs = Object.freeze({ ...inputs }) as TInputs;
}
}
```
### Resource Group Base
```javascript
import { Construct } from 'constructs';
import { InputContract, OutputContract, HasOutputs } from './core-types';
export abstract class ABCResourceGroup<
TInputs extends InputContract,
TOutputs extends OutputContract
> extends Construct implements HasOutputs<TOutputs> {
public abstract readonly outputs: TOutputs;
protected readonly inputs: TInputs;
protected constructor(scope: Construct, id: string, inputs: TInputs) {
super(scope, id);
this.inputs = Object.freeze({ ...inputs }) as TInputs;
}
}
```
## Logical Units & Resource Groups (Canonical Example)
Below is the full 3tier example implemented in CDK.
### Data Logical Unit
```default
src/data/index.ts
src/data/storage/index.ts
src/data/database/index.ts
```
```javascript
import { Construct } from 'constructs';
import { ABCLogicalUnit } from '../abc/logical-unit';
import { StorageGroup } from './storage';
import { DatabaseGroup } from './database';
export interface InputContract {
environment: string;
region: string;
storageClass: string;
dbEngine: string;
dbInstanceSize: string;
}
export interface OutputContract {
storageBucketName: string;
databaseEndpoint: string;
}
export class DataUnit extends ABCLogicalUnit<InputContract, OutputContract> {
public readonly outputs: OutputContract;
constructor(scope: Construct, id: string, inputs: InputContract) {
super(scope, id, inputs);
const storage = new StorageGroup(this, 'Storage', {
environment: inputs.environment,
region: inputs.region,
storageClass: inputs.storageClass,
});
const database = new DatabaseGroup(this, 'Database', {
environment: inputs.environment,
dbEngine: inputs.dbEngine,
dbInstanceSize: inputs.dbInstanceSize,
});
this.outputs = {
storageBucketName: storage.outputs.storageBucketName,
databaseEndpoint: database.outputs.databaseEndpoint,
};
}
}
```
#### Storage Resource Group
```default
import { Construct } from 'constructs';
import { ABCResourceGroup } from '../../abc/resource-group';
export interface InputContract {
environment: string;
region: string;
storageClass: string;
}
export interface OutputContract {
storageBucketName: string;
}
export class StorageGroup extends ABCResourceGroup<InputContract, OutputContract> {
public readonly outputs: OutputContract;
constructor(scope: Construct, id: string, inputs: InputContract) {
super(scope, id, inputs);
this.outputs = {
storageBucketName: 'bucket-name-placeholder',
};
}
}
```
#### Database Resource Group
```default
import { Construct } from 'constructs';
import { ABCResourceGroup } from '../../abc/resource-group';
export interface InputContract {
environment: string;
dbEngine: string;
dbInstanceSize: string;
}
export interface OutputContract {
databaseEndpoint: string;
}
export class DatabaseGroup extends ABCResourceGroup<InputContract, OutputContract> {
public readonly outputs: OutputContract;
constructor(scope: Construct, id: string, inputs: InputContract) {
super(scope, id, inputs);
this.outputs = {
databaseEndpoint: 'db-endpoint-placeholder',
};
}
}
```
### Logic Logical Unit
```default
src/logic/index.ts
src/logic/compute/index.ts
src/logic/messaging/index.ts
```
Compute Resource Group and Messaging Resource Group follow the same pattern.
### Presentation Logical Unit
```default
src/presentation/index.ts
src/presentation/webapp/index.ts
src/presentation/cdn/index.ts
```
WebApp Resource Group and CDN Resource Group follow the same pattern.
## Application Stack
```javascript
import { Construct } from 'constructs';
import { ABCApplicationStack } from './abc/application-stack';
import { DataUnit } from './data';
import type { InputContract as DataUnitInput } from './data';
import { LogicUnit } from './logic';
import type { InputContract as LogicUnitInput } from './logic';
import { PresentationUnit } from './presentation';
import type { InputContract as PresentationUnitInput } from './presentation';
export interface InputContract {
environment: string;
region: string;
globalTags?: Record<string, string>;
}
export interface OutputContract {
frontendUrl: string;
apiEndpoint: string;
}
export class AppStack extends ABCApplicationStack<OutputContract> {
public readonly outputs: OutputContract;
constructor(scope: Construct, id: string, inputs: InputContract) {
super(scope, id);
const dataInputs: DataUnitInput = {
environment: inputs.environment,
region: inputs.region,
storageClass: 'STANDARD',
dbEngine: 'postgres',
dbInstanceSize: 'db.t3.micro',
};
const dataUnit = new DataUnit(this, 'DataUnit', dataInputs);
const logicInputs: LogicUnitInput = {
environment: inputs.environment,
region: inputs.region,
computeSize: 'small',
messageRetention: 1209600,
databaseEndpoint: dataUnit.outputs.databaseEndpoint,
};
const logicUnit = new LogicUnit(this, 'LogicUnit', logicInputs);
const presentationInputs: PresentationUnitInput = {
environment: inputs.environment,
region: inputs.region,
frontendAssetsBucket: dataUnit.outputs.storageBucketName,
apiEndpoint: logicUnit.outputs.apiEndpoint,
};
const presentationUnit = new PresentationUnit(this, 'PresentationUnit', presentationInputs);
this.outputs = {
frontendUrl: presentationUnit.outputs.frontendUrl,
apiEndpoint: logicUnit.outputs.apiEndpoint,
};
}
}
```

21
profiles/index.md Normal file
View file

@ -0,0 +1,21 @@
# Profiles
Profiles define how the ABC Pattern maps onto specific IaC tools. Each profile
introduces additional rules, conventions, and examples tailored to the target
system.
Profiles use identifiers of the form:
```default
ABC-PROFILE-<PROFILE>-R#
```
Current profiles include:
* imperative, objectoriented implementations
* declarative modulebased implementation
Profiles demonstrate that ABC is not tied to any particular paradigm.
* [CDK TypeScript Profile](cdk-ts.md)
* [Terraform Profile](tf.md)

199
profiles/tf.md Normal file
View file

@ -0,0 +1,199 @@
# Terraform Profile
## Concept → Terraform Mapping
| ABC Concept | Meaning | Terraform Mapping |
|---------------|-------------------------|----------------------------------------------------|
| ABCC0 | Construct | Terraform module |
| ABCC1 | Application Stack | Root Terraform module |
| ABCC2 | Logical Unit | Child module representing a domain |
| ABCC3 | Resource Group | Submodule representing a cohesive resource cluster |
| ABCC4 | Input Contract | variables.tf in a module |
| ABCC5 | Output Contract | outputs.tf in a module |
| ABCC6 | Instantiation Interface | `module "" { ... }` block |
| ABCC7 | Capturing Down | Passing variables from parent to child module |
| ABCC8 | Bubbling Up | Exposing outputs from child modules to parent |
## Proile Rules
Terraform profile rules follow the canonical identifier format:
```default
ABC-PROFILE-TF-R#
```
These rules are profilespecific, not core ABC rules.
### ABC-PROFILE-TF-R1 (SHOULD)
Each ABC construct SHOULD be implemented as a Terraform module.
### ABC-PROFILE-TF-R2 (SHOULD)
The directory structure SHOULD reflect the ABC hierarchy:
```default
root/
main.tf
data/
main.tf
storage/
main.tf
database/
main.tf
logic/
main.tf
presentation/
main.tf
```
### ABC-PROFILE-TF-R3 (SHOULD)
Each module SHOULD contain:
* main.tf
* variables.tf (InputContract)
* outputs.tf (OutputContract)
### ABC-PROFILE-TF-R4 (MUST)
Module inputs MUST be declared exclusively in variables.tf.
### ABC-PROFILE-TF-R5 (MUST)
Module outputs MUST be declared exclusively in outputs.tf.
### ABC-PROFILE-TF-R6 (MUST)
Modules MUST NOT reference parent or sibling modules directly; all data MUST
flow through variables and outputs.
(This enforces ABCR22, ABCR40, ABCR42.)
### ABC-PROFILE-TF-R7 (MUST)
Modules MUST be instantiated using a module “<name>” { … } block with explicit
variable assignments.
### ABC-PROFILE-TF-R8 (MUST)
Modules MUST NOT read Terraform state from other modules except via outputs.
### ABC-PROFILE-TF-R9 (MUST)
Capturing Down MUST be implemented by passing parent variables or outputs into
child module inputs.
### ABC-PROFILE-TF-R10 (MUST)
Bubbling Up MUST be implemented by exposing child module outputs and reexposing
them in the parent module if needed.
### ABC-PROFILE-TF-R11 (MUST)
Resource definitions MUST reside only in Resource Group modules (ABCC3).
### ABC-PROFILE-TF-R12 (MUST)
Logical Units MUST NOT contain Terraform resources directly.
### ABC-PROFILE-TF-R13 (SHOULD)
Logical Units SHOULD only orchestrate child modules and expose aggregated
outputs.
## Canonical Example
A minimal 3tier ABC architecture in Terraform.
### Application Stack
```hcl
module "data" {
source = "./data"
environment = var.environment
region = var.region
}
module "logic" {
source = "./logic"
environment = var.environment
region = var.region
database_endpoint = module.data.database_endpoint
}
module "presentation" {
source = "./presentation"
environment = var.environment
region = var.region
frontend_assets_bucket = module.data.storage_bucket_name
api_endpoint = module.logic.api_endpoint
}
output "frontend_url" {
value = module.presentation.frontend_url
}
output "api_endpoint" {
value = module.logic.api_endpoint
}
```
```hcl
variable "environment" { type = string }
variable "region" { type = string }
```
### Data Logical Unit
```default
module "storage" {
source = "./storage"
environment = var.environment
region = var.region
storage_class = var.storage_class
}
module "database" {
source = "./database"
environment = var.environment
db_engine = var.db_engine
db_instance_size = var.db_instance_size
}
output "storage_bucket_name" {
value = module.storage.bucket_name
}
output "database_endpoint" {
value = module.database.endpoint
}
```
```default
variable "environment" { type = string }
variable "region" { type = string }
variable "storage_class" { type = string }
variable "db_engine" { type = string }
variable "db_instance_size" { type = string }
```
#### Storage Resource Group
```hcl
resource "aws_s3_bucket" "bucket" {
bucket = "${var.environment}-storage"
}
```
```hcl
variable "environment" { type = string }
variable "region" { type = string }
variable "storage_class" { type = string }
```
```hcl
output "bucket_name" {
value = aws_s3_bucket.bucket.bucket
}
```