Phase 2 -- Root Updates -- Exports
The cross-phase contracts Phase 2 produces. Downstream phases (Phase 3 Corporate, Phase 4 Runtime Platform) consume these contracts to compose their own stacks.
This document complements specification.md — the spec describes what Phase 2 does; this document describes what other phases see once Phase 2 has landed.
1. CloudFormation stack exports
Section titled “1. CloudFormation stack exports”RootDnsStack (CFN stack name RootConfiguration) publishes the following exports. Names that exist today are preserved; names new in Phase 2 are flagged as such.
| Export name | Value type | Meaning | Status | Consumers |
|---|---|---|---|---|
arda-app-zone | Hosted Zone ID | app.arda.cards | Preserved | Existing partition / ingress stacks |
arda-io-zone | Hosted Zone ID | io.arda.cards | Preserved | Existing partition / ingress stacks |
arda-auth-zone | Hosted Zone ID | auth.arda.cards | Preserved | Existing partition / ingress stacks |
arda-assets-zone | Hosted Zone ID | assets.arda.cards | Preserved | Existing partition / ingress stacks |
arda-allow-create-ns-record-role | IAM Role ARN | AllowCreatingNSRecordsRole ARN — assume-role target for cross-account NS-delegation writes | Preserved | Phase 3 (Corporate stack), Phase 4 (per-partition stacks), existing partition IngressStacks |
arda-ardamails-zone | Hosted Zone ID | ardamails.com mail-root zone | New (Phase 2) | Phase 3 (Corporate stack composing WriteNSRecordsToUpstreamDns against the parent zone), Phase 4 (per-partition stacks doing the same for partition sub-zones) |
How downstream phases consume these exports
Section titled “How downstream phases consume these exports”Phase 3 / Phase 4 stacks read these via the existing stackTypes.readImports() helper used by every consuming stack today, e.g.:
import * as rootDns from "arda/stacks/root/root-dns-stack";
const rootImports = rootDns.importValues();// rootImports.ardamailsZone -> "Z0123456789ABCDEFG" (zone ID at runtime)// rootImports.allowCreateNsRecordRole -> arn:aws:iam::<root-acct>:role/AllowWriteNsRecordsBoth values resolve to CloudFormation Fn::ImportValue references at synth time, so a stack consuming them must be deployed after the Root stack and within the same CloudFormation account boundary or via cross-account stack imports as appropriate.
2. TypeScript exports from instances/Root/dns.ts
Section titled “2. TypeScript exports from instances/Root/dns.ts”The new declarative configuration file in Phase 2:
/** All zone names this instance group declares. */export const ROOT_ZONE_NAMES = { app: "app.arda.cards", io: "io.arda.cards", auth: "auth.arda.cards", assets: "assets.arda.cards", ardamails: "ardamails.com",} as const;
/** CloudFormation export keys this instance group publishes. */export const ROOT_EXPORT_KEYS = [ "appZone", "ioZone", "authZone", "assetsZone", "ardamailsZone", "allowCreateNsRecordRole",] as const;
export type RootExportKey = (typeof ROOT_EXPORT_KEYS)[number];(The exact symbol shape is finalised at write time; the contract is that instances/Root/dns.ts declares the zones and export keys as the single source of truth used by apps/Root/r53-zones.ts and consumed by tests in verification.md.)
3. TypeScript exports from stacks/root/root-dns-stack.ts
Section titled “3. TypeScript exports from stacks/root/root-dns-stack.ts”After the rename, the stack module’s public surface is:
export class RootDnsStack extends cdk.Stack { ... }
export interface Built { readonly appZone: string; readonly ioZone: string; readonly authZone: string; readonly assetsZone: string; readonly ardamailsZone: string; // NEW in Phase 2 readonly allowCreateNsRecordRole: iam.IRole;}
export type ExportKeys = | "appZone" | "ioZone" | "authZone" | "assetsZone" | "ardamailsZone" // NEW in Phase 2 | "allowCreateNsRecordRole";
export interface ExportDefinition extends Record<ExportKeys, stackTypes.StackIODefinition> {}export interface ExportValues extends Record<ExportKeys, stackTypes.StackIOValue> {}
/** Read the cross-stack imports for the Root stack's exports. */export function importValues(): ExportValues { ... }The class name change (RootConfigurationStack → RootDnsStack) is the only breaking TypeScript change; in-repo callers are updated as part of Task 2 in specification.md.
4. External resources Phase 2 references but does NOT create
Section titled “4. External resources Phase 2 references but does NOT create”For traceability, the resources Phase 2 reads / depends on but does not own:
| Resource | Owner | How Phase 2 references it |
|---|---|---|
ardamails.com registrar record (Route53 domain registration in platformRoot account) | Already-registered domain in AWS Route53 | The PublicHostedZone Phase 2 creates becomes the authoritative zone for the registered domain. Registrar-side NS configuration (the four AWS nameservers) is handled outside CDK — the operator confirms registrar NS values match the Route53-assigned NS values once after first deploy. (Manual; not a Phase 2 task because the four NS values are stable across CDK redeploys.) |
AllowCreatingNSRecordsRole (IAM role) | Already exists in RootConfigurationStack today; carries over to RootDnsStack | Preserved verbatim through the rename. |
WriteNSRecordsToUpstreamDns construct | Already exists at src/main/cdk/constructs/xgress/write-ns-records-to-upstream-dns.ts | Not instantiated by Phase 2. Phase 3 / Phase 4 instantiate it with targetAccountId = Root account ID. |
inline-lambdas/write-platform-root-ns-record.ts (Lambda body) | Already exists | Phase 2 leaves this file untouched. |
5. Surfaces Phase 2 does NOT add or remove
Section titled “5. Surfaces Phase 2 does NOT add or remove”For clarity, the following surfaces are not changed by Phase 2:
- No new IAM roles.
AllowCreatingNSRecordsRoleis preserved; no new role is created. - No new stack class beyond the rename.
RootDnsStackis the renamedRootConfigurationStack; no second stack is added in this phase. - No new GitHub Actions workflows. Phase 2 introduces no new CI surface.
- No CloudFormation export removed. Every export present today is preserved.
6. Downstream consumption catalogue
Section titled “6. Downstream consumption catalogue”The following phases consume the exports Phase 2 produces. Each row describes the consumption pattern for forward traceability (so a future agent reading the Phase 3 spec can find its upstream contract here).
| Consumer phase | Consumes | Pattern |
|---|---|---|
| Phase 3 (Corporate) | arda-ardamails-zone, arda-allow-create-ns-record-role | Corporate stack instantiates r53.PublicHostedZone(this, "ArdaCorpZone", { zoneName: "arda.ardamails.com" }), then new WriteNSRecordsToUpstreamDns(this, "WriteArdaDelegationNs", { targetAccountId: ROOT_ACCOUNT_ID, hostingZoneName: "ardamails.com", subdomain: "arda", nameServers: corpZone.hostedZoneNameServers }). The WriteNSRecordsToUpstreamDns construct internally builds the assume-role ARN from the well-known role name (ALLOW_WRITE_NS_RECORDS_ROLE.name) so explicit consumption of the arda-allow-create-ns-record-role export is optional. |
| Phase 4 (Runtime Platform) | arda-ardamails-zone, arda-allow-create-ns-record-role | Each partition stack instantiates r53.PublicHostedZone({ zoneName: "<partition>.ardamails.com" }), then new WriteNSRecordsToUpstreamDns(this, "Write<Partition>DelegationNs", { targetAccountId: ROOT_ACCOUNT_ID, hostingZoneName: "ardamails.com", subdomain: "<partition>", nameServers: partitionZone.hostedZoneNameServers }). Same pattern as Phase 3, one instantiation per partition. |
7. References
Section titled “7. References”analysis.md— gap analysis.requirements.md— numbered requirements.specification.md— task contract.verification.md— test catalogue.../phases.md— phase plan; Phase 3 / Phase 4 sections reference the consumption pattern above.../decision-log.md— decisions includingDQ-R1-006.
Copyright: © Arda Systems 2025-2026, All rights reserved