/** * Application backup tier — the disaster-recovery posture an app declares * once (`App.getApp(name, { backup: { tier } })`) and every tier-derived * default reads. The vocabulary AND the per-tier defaults table live here so * the constructs (which synthesise the defaults), the generator (whose * presets and schemas speak the vocabulary) and every test that asserts what * a tier promises derive from one declaration instead of copies kept in step * by hand. * * Independent of the two other tier axes: the account governance tier * ([[ACCOUNT_TIERS]]) and the generator pattern tier (`TIER_NAMES`). */ import { z } from "zod"; export declare const BACKUP_TIERS: readonly ["standard", "resilient", "enterprise"]; export type BackupTier = (typeof BACKUP_TIERS)[number]; export declare const BackupTierSchema: z.ZodEnum<{ standard: "standard"; resilient: "resilient"; enterprise: "enterprise"; }>; /** Type guard: checks whether a string is a declared application backup tier. */ export declare function isBackupTier(value: string): value is BackupTier; /** * Every default the app-level backup tier owns. One row per tier, one column * per knob; a construct reads its column through [[tierDefault]] and never * spells the value itself, so the tier→default derivation has exactly one * home. An explicit prop on the construct still beats the tier column. */ export interface BackupTierDefaults { /** S3 bucket versioning (`S3Bucket.versioned`). */ readonly s3Versioned: boolean; /** * RDS Instance / Aurora / Global Aurora automated backup retention in days * (`backupRetention`). The read replica keeps CloudFormation's 0 — replica * retention is a create-time property, so a tier flip would replace it. */ readonly rdsBackupRetentionDays: number; /** * Service-side delete guards on the resources CloudFormation would refuse * to delete while they are on: DynamoDB `DeletionProtectionEnabled` and * the ELBv2 `deletion_protection.enabled` attribute (the load balancer * guard additionally applies only in the production environment — a * dev/staging stack is destroyed daily by design). RDS deletion * protection is NOT tier-owned: the database constructs default it ON at * every tier. The destroy pre-flight * (`deploy-core/src/orchestration/application/destroyPreFlight.ts`) * switches every guard off before a consented destroy, so a tier that * turns one on never wedges `fjall destroy` or a CI destroy action. */ readonly deletionProtection: boolean; /** * Encrypt with the stack's shared customer-managed KMS key instead of the * AWS-managed default: DynamoDB tables, SNS topics, Lambda environment * variables, ECS Exec session logging, and the CloudWatch log groups the * tier-aware constructs create. ECR and RDS/Aurora storage keep their own * knobs — each is a create-only property, so flipping it from a tier would * replace live data. The Secrets Manager key is a different case: it is an * in-place property (the registry seed at * `deploy-core/src/services/infrastructure/cfnRegistrySeed.ts` lists only * `Name` as create-only), and today every Fjall-minted secret carries its * own per-secret key at every tier, untiered. Bringing that key under this * column is an open raise of the backup-tier owned-defaults design (R1 of * its 2026-09-05 follow-ups), not a decision this column has taken. */ readonly customerManagedKeys: boolean; /** ECS Container Insights (enhanced observability) on the cluster. */ readonly containerInsights: boolean; /** * Application load balancer access logs, delivered to the stack's * lifecycle-expired access-log bucket. */ readonly albAccessLogs: boolean; /** * CloudFront standard logging (v2, CloudWatch-vended) to the same * access-log bucket, as JSON. */ readonly cloudFrontLogging: boolean; /** Lambda active X-Ray tracing. */ readonly lambdaTracing: boolean; /** * RDS Database Insights mode when the construct has no explicit * `databaseInsights.mode`; `advanced` carries 15 months of Performance * Insights retention. */ readonly databaseInsightsMode: "standard" | "advanced"; } /** * The tier table. `standard` is also the column an app with no tier (or * `backup: false`) runs — declaring `standard` adds the DR tag and changes * no default — so the untiered column is this one, not a fourth row. */ export declare const BACKUP_TIER_DEFAULTS: Readonly>; /** * The column an app with no tier (no `backup` on the App, or `backup: false`) * runs. Declaring it is free by construction — the same defaults plus the DR * tag — which is why the webapp's posture cure proposes exactly this tier. */ export declare const DEFAULT_BACKUP_TIER = "standard"; /** * The tier-owned default for one knob. An undefined tier reads the * [[DEFAULT_BACKUP_TIER]] column. */ export declare function tierDefault(tier: BackupTier | undefined, knob: K): BackupTierDefaults[K]; /** * The tag key AWS Backup plan selection rules match on. `BackupPlan` builds * its selection from this key alone — the selection carries no resource-type * filter, so the tag IS the selection scope — and the constructs that own a * resource AWS Backup can protect stamp it at construction (`tagBackupTier`, * called by the RDS instance, the Aurora cluster, the DynamoDB table, the * ClickHouse data volume and a versioned bucket). It is not applied across * the app, and no aspect applies it. The webapp's posture rules * (`assetParser`, `missing-dr-tier-tag`) read it back from discovered * resources and re-spell it until they import this — TODO 2026-09-14, * owner: paul — tracked in the 2026-09-05 remediation-raises build * prompt, § 10 Train E-webapp record ("util fold"). */ export declare const BACKUP_TIER_TAG_KEY = "fjall:disasterRecovery:tier"; /** * Application backup tier → AWS Backup plan tag VALUE. `standard` maps to * `default` (the plan every untiered resource joins), the other tiers to * their own name. `Record` is the presence guard: a new * tier without a row fails typecheck here. The webapp's tag-value vocabulary * re-spells these until it imports this map — same TODO as the key above. */ export declare const BACKUP_TIER_TAG_MAP: Readonly>;