Frontend Pipeline — Development Blueprint
Step-by-step development blueprint for the frontend deployment pipeline. Each step corresponds to a phase in the Design Analysis Development Sequence, expanded with specific file changes, acceptance criteria, and verification mechanisms.
References
Section titled “References”- Project Goal and Current State
- Design Analysis
- Amplify App Provisioning — How It Works
- Front End Code Repository
- Infrastructure Definition
- Purpose Configuration
- Example of back-end deployment
Step 1 — Demo Environment Setup
Section titled “Step 1 — Demo Environment Setup”Preconditions
Section titled “Preconditions”- The Alpha001 account (
009765408297) has a fully provisioneddemopartition (CDK infrastructure: Cognito, Aurora DB, API Gateway, DNS atdemo.app.arda.cards, Secrets Manager entries forAlpha001-demo-*). This was deployed by a previousamm.sh Alpha001 demorun. - The
arda-frontend-apprepository exists in theArda-cardsGitHub organization. - The
AMPLIFY_GITHUB_ACCESSTOKENGitHub org secret (or 1Password entry) grants read access to thearda-frontend-apprepository. - The
ARDA_API_KEY_DEMOGitHub org secret exists (provisioned byinfrastructure/tools/sync-secrets-from-1password.sh). - The
infrastructurerepositorymainbranch is the deployment source for theamm.ymlworkflow.
Purpose
Section titled “Purpose”Create an isolated Amplify application in the demo partition (Alpha001) connected to a demo branch, with auto-build disabled. This provides a safe testing ground for the new deployment pipeline without touching any existing Amplify apps.
Repositories Affected
Section titled “Repositories Affected”arda-frontend-app(create branch)infrastructure(modify CloudFormation template)- Alpha001 AWS account (deploy CloudFormation stacks)
Changes Needed
Section titled “Changes Needed”Create: demo branch in arda-frontend-app
Section titled “Create: demo branch in arda-frontend-app”Create the branch off main. No code changes needed — the branch exists solely so the new Amplify app has something to connect to.
Modify: infrastructure/src/main/cfn/amplifyBranch.cfn.yaml
Section titled “Modify: infrastructure/src/main/cfn/amplifyBranch.cfn.yaml”Two changes:
1. Add an EnableAutoBuild parameter so it can be controlled at deployment time:
Parameters: # ... existing parameters ... EnableAutoBuild: Type: String Default: "true" AllowedValues: ["true", "false"] Description: "Whether Amplify auto-builds on push to the connected branch"Update the AWS::Amplify::Branch resource to use the parameter:
EnableAutoBuild: !Ref EnableAutoBuildThe default is true, which preserves the current behavior for all existing deployments. The SandboxKyle002 (kyle) deployment does not pass this parameter, so it gets the default — no behavior change.
2. Add an AmplifyBranchName export so the GitHub Actions workflow can read the branch name from CloudFormation:
Outputs: AmplifyBranchName: Description: The Amplify branch resource name Value: !Ref Branch Export: Name: !Sub "${Infrastructure}-${Partition}-I-AmplifyBranchName"This export is consumed by the reusable deployment workflow alongside the existing AmplifyAppId export from amplify.cfn.yaml.
Modify: infrastructure/amm.sh — update the Amplify gate, branch mapping, and export stacks
Section titled “Modify: infrastructure/amm.sh — update the Amplify gate, branch mapping, and export stacks”Gate condition. The current gate on line 465 excludes Alpha001 and Alpha002 from the Amplify deployment steps:
# Current — blocks Alpha001/Alpha002if [[ "${infrastructure}" != "Alpha001" && "${infrastructure}" != "Alpha002" ]]; thenThis must be updated to check a list of allowed (Infrastructure, Partition) pairs. The list is a constant in amm.sh:
AMPLIFY_DEPLOY_TARGETS=("SandboxKyle002:kyle" "Alpha001:demo")Partition-to-branch-name mapping. The Amplify branch resource names are a legacy of the original branch-sync model — the prod app’s branch resource is named main (not prod). Rather than special-casing this, amm.sh defines a uniform mapping for all partitions:
declare -A AMPLIFY_BRANCH_NAMES=( [dev]="dev" [stage]="stage" [demo]="demo" [prod]="main" [kyle]="main")The mapping is used when deploying the AmplifyBranch stack (as the Branch parameter) and when deploying lightweight export stacks for existing apps. This is the single source of truth for branch names — the workflow never derives or assumes them.
Repo/AppName parameterization. Currently hardcoded to kyle-frontend-app. Maintained as an explicit mapping in amm.sh (alongside the existing AMPLIFY_BRANCH_NAMES and AMPLIFY_DEPLOY_TARGETS constants), keyed by (Infrastructure, Partition). No new properties are added to purpose-configuration.
EnableAutoBuild parameter. Pass EnableAutoBuild=false for the demo partition’s AmplifyBranch stack:
branch_name="${AMPLIFY_BRANCH_NAMES[${partition}]}"aws cloudformation deploy \ --stack-name "${infrastructure}-${partition}-AmplifyBranch" \ --template-file "src/main/cfn/amplifyBranch.cfn.yaml" \ --parameter-overrides \ "Infrastructure=${infrastructure}" "Partition=${partition}" \ "Branch=${branch_name}" "EnableAutoBuild=false"Create: infrastructure/src/main/cfn/amplifyExports.cfn.yaml
Section titled “Create: infrastructure/src/main/cfn/amplifyExports.cfn.yaml”A lightweight CloudFormation template that publishes AmplifyAppId and AmplifyBranchName as CloudFormation exports. Used for existing manually-created Amplify apps (dev, stage, prod) that have no CloudFormation stacks and therefore no exports. This gives the GitHub Actions workflow a uniform lookup mechanism.
AWSTemplateFormatVersion: "2010-09-09"Description: "Publish Amplify App ID and Branch Name as CloudFormation exports"
Parameters: Infrastructure: Type: String Partition: Type: String AmplifyAppId: Type: String Description: "The existing Amplify App ID" AmplifyBranchName: Type: String Description: "The Amplify branch resource name"
Outputs: AmplifyAppId: Value: !Ref AmplifyAppId Export: Name: !Sub "${Infrastructure}-${Partition}-I-AmplifyAppId" AmplifyBranchName: Value: !Ref AmplifyBranchName Export: Name: !Sub "${Infrastructure}-${Partition}-I-AmplifyBranchName"The amm.sh script deploys this stack for partitions that have existing Amplify apps but are not in the AMPLIFY_DEPLOY_TARGETS list. At cutover, the dev/stage/prod entries are added to trigger these lightweight stacks. The stack name follows the standard pattern: ${infrastructure}-${partition}-AmplifyExports.
Modify: infrastructure/.github/workflows/amm.yml — fix secret selection
Section titled “Modify: infrastructure/.github/workflows/amm.yml — fix secret selection”The workflow currently hardcodes Kyle/Stage-specific secrets for the ARDA_API_KEY. Per-environment API key secrets already exist as GitHub org secrets (provisioned by infrastructure/tools/sync-secrets-from-1password.sh): ARDA_API_KEY_DEV, ARDA_API_KEY_STAGE, ARDA_API_KEY_DEMO, ARDA_API_KEY_PROD, ARDA_API_KEY_KYLE.
Update the ARDA_API_KEY env var to use dynamic secret selection:
ARDA_API_KEY: "${{ secrets[format('ARDA_API_KEY_{0}', steps.partition.outputs.partition)] }}"The other four secrets (ARDA_SIGNUP_KEY, HUBSPOT_CLIENT_KEY, HUBSPOT_PAT, PYLON_WIDGET_KEY) are shared across environments and can remain as-is. The partition names (demo, dev, stage, prod, kyle) match the secret name suffixes exactly.
Deploy via the amm GitHub Actions workflow
Section titled “Deploy via the amm GitHub Actions workflow”The infrastructure repo has an amm.yml workflow (workflow_dispatch) that runs amm.sh. The deployment is triggered by selecting Alpha001/demo from the environment dropdown — this option already exists in the workflow.
The workflow:
- Fetches purpose-configuration for the
demopartition - Assumes the
Alpha001-I-GitHubActionInfrastructurerole via OIDC - Runs
./amm.sh Alpha001 demo
This runs the full amm.sh sequence: CDK infrastructure, EKS logging, load balancer, external secrets, nginx, target groups, partition secrets (with the correct ARDA_API_KEY_DEMO), and (after the gate is updated) the Amplify stacks.
Alternative: Local deployment
Section titled “Alternative: Local deployment”The stacks can also be deployed locally via amm.sh Alpha001 demo with the right AWS profile and 1Password secrets. The local path reads ARDA_API_KEY from 1Password (Arda-SandboxKyle/ARDA-API-KEY), which is Kyle-specific — if deploying locally, override it with the correct demo value: export ARDA_API_KEY="$(op read 'op://Arda-DemoOAM/ARDA-API-KEY/password')" before running amm.sh.
Acceptance Criteria
Section titled “Acceptance Criteria”- The
demobranch exists inarda-frontend-app amplifyBranch.cfn.yamlacceptsEnableAutoBuildas a parameter with defaulttrueamplifyBranch.cfn.yamlexports${Infrastructure}-${Partition}-I-AmplifyBranchNameamplifyExports.cfn.yamlexists as the lightweight export templateamm.shhas a partition-to-branch-name mapping constant and anAMPLIFY_DEPLOY_TARGETSallow-list- The
amm.shgate condition allows thedemopartition on Alpha001 to execute the Amplify steps - The
amm.shAmplify steps use an explicitRepo/AppNamemapping constant (usesarda-frontend-appfor Alpha001/demo) - The
amm.ymlworkflow usessecrets[format('ARDA_API_KEY_{0}', partition)]for per-environment secret selection - The existing Kyle deployment (
SandboxKyle002) is unaffected by all template, script, and workflow changes Alpha001-demo-Amplifystack is deployed with thedemopartition’s environment variables and correct secretsAlpha001-demo-AmplifyBranchstack is deployed withEnableAutoBuild=false- CloudFormation exports
Alpha001-demo-I-AmplifyAppIdandAlpha001-demo-I-AmplifyBranchNameare available - The Amplify app exists and is connected to the
demobranch - The initial deployment completes successfully (triggered by
start-jobas part of theamm.shexecution — see Step 2.5.4 in Amplify App Provisioning) - The site at
demo.app.arda.cardsloads and is functional
Verification
Section titled “Verification”Before deployment — template and script validation:
- Validate the template:
aws cloudformation validate-template --template-body file://src/main/cfn/amplifyBranch.cfn.yaml - Review the
amm.shchanges: confirm the gate condition allows Alpha001/demo and theRepo/AppNameare correct
Kyle regression check:
- Deploy to Kyle first: trigger the
ammworkflow withSandboxKyle002/kyle(or runamm.sh SandboxKyle002 kylelocally) - Verify the Kyle
AmplifyBranchstack updates successfully (or reports “No changes to deploy”) - Verify Kyle auto-build is still enabled:
aws amplify get-branch --app-id {kyle-app-id} --branch-name main --query "branch.enableAutoBuild"returnstrue - Push a commit to
kyle-frontend-appmainand confirm auto-build triggers
Demo deployment:
- Trigger the
ammworkflow withAlpha001/demo(or runamm.sh Alpha001 demolocally) - Verify the branch exists:
git ls-remote --heads origin demo - Verify the stacks:
aws cloudformation describe-stacks --stack-name Alpha001-demo-AmplifyandAlpha001-demo-AmplifyBranch - Verify auto-build is disabled:
aws amplify get-branch --app-id {id} --branch-name demo --query "branch.enableAutoBuild"returnsfalse - Verify the site loads at
demo.app.arda.cardsafter the initialstart-job
Step 2 — Infrastructure (IAM Role)
Section titled “Step 2 — Infrastructure (IAM Role)”Preconditions
Section titled “Preconditions”- Step 1 is complete: the
Alpha001-demo-AmplifyandAlpha001-demo-AmplifyBranchCloudFormation stacks are deployed and the demo Amplify app is functional. - The
infrastructurerepository changes from Step 1 (amplifyBranch.cfn.yaml,amm.sh,amm.yml) are merged tomain. - AWS CLI access to both Alpha001 (
009765408297) and Alpha002 (139852620346) accounts is available (viaamm.shlocally or theamm.ymlworkflow).
Purpose
Section titled “Purpose”Create the dedicated frontend IAM role in both AWS accounts (Alpha001 and Alpha002). The role grants GitHub Actions permission to trigger Amplify deployments and poll their status.
Repositories Affected
Section titled “Repositories Affected”infrastructure
Changes Needed
Section titled “Changes Needed”Modify: src/main/cdk/constructs/oam/gh-oidc-provider.ts
Section titled “Modify: src/main/cdk/constructs/oam/gh-oidc-provider.ts”Add a new frontendDeploymentRole() private method alongside the existing role methods. The new role:
- Name:
${prefix}-API-GitHubActionFrontEnd - OIDC trust:
repo:Arda-cards/arda-frontend-appscoped torefs/heads/main,refs/heads/patch, andrefs/heads/demo - Permissions:
amplify:StartJob— trigger buildsamplify:GetJob— poll deployment statusamplify:GetApp— resolve app metadataamplify:GetBranch— resolve branch metadatacloudformation:ListExports— read Amplify App ID and Branch Name from CloudFormation exports
- Resource scope: Amplify:
arn:aws:amplify:${region}:${account}:apps/*. CloudFormation:*(ListExports does not support resource-level restrictions).
Expose the new role via the GhOidcProviderBuilt interface.
Deploy to both accounts
Section titled “Deploy to both accounts”amm.sh Alpha001 demo prod— deploys to Alpha001 (demo + prod partitions)amm.sh Alpha002 dev stage— deploys to Alpha002 (dev + stage partitions)
The role is part of the infrastructure-level CDK app, so it deploys alongside the existing OIDC constructs with no separate step.
Acceptance Criteria
Section titled “Acceptance Criteria”- The
GhOidcProviderconstruct creates a fourth role (${prefix}-API-GitHubActionFrontEnd) alongside the existing three npx cdk synthsucceeds for both Alpha001 and Alpha002 infrastructure apps- The synthesized CloudFormation template contains the new role with the correct OIDC trust conditions and Amplify permissions
amm.shdeploys successfully to both accounts- The role exists in both accounts after deployment
- A GitHub Actions workflow on the
demobranch ofarda-frontend-appcan assume the role in Alpha001 (verified via a temporary minimal test workflow — see Verification below)
Verification
Section titled “Verification”- Run
npx cdk synthand inspect the generated template for the role - Deploy via
amm.shto both accounts - Verify the role:
aws iam get-role --role-name Alpha001-API-GitHubActionFrontEnd(Alpha001) andaws iam get-role --role-name Alpha002-API-GitHubActionFrontEnd(Alpha002) - Test OIDC assume: create a temporary minimal workflow (
.github/workflows/test-oidc.yaml) on thedemobranch that assumes the role and runsaws sts get-caller-identity. This workflow is deleted in Step 3 when the real workflows are created.
Step 3 — Workflow Development
Section titled “Step 3 — Workflow Development”Preconditions
Section titled “Preconditions”- Step 1 is complete: the
demobranch exists inarda-frontend-appand the demo Amplify app is deployed and functional atdemo.app.arda.cards. CloudFormation exportsAlpha001-demo-I-AmplifyAppIdandAlpha001-demo-I-AmplifyBranchNameare available. - Step 2 is complete: the
Alpha001-API-GitHubActionFrontEndIAM role exists and can be assumed via OIDC from thedemobranch. - The
Arda-cards/purpose-configuration-actionGitHub Action is available (used by the backend; no changes needed). - The
ARDA_PURPOSE_LOCATOR_READER_TOKENandARDA_PURPOSE_LOCATOR_BASE_URLorg-level secrets/vars exist (used by the backend workflows).
Purpose
Section titled “Purpose”Create the GitHub Actions workflows on the demo branch. The workflows use StartJob to trigger Amplify builds and GetJob to poll status. All build and environment variable logic remains within Amplify.
Repositories Affected
Section titled “Repositories Affected”arda-frontend-app(ondemobranch)arda-frontend-app(GitHub settings — environments)
Changes Needed
Section titled “Changes Needed”Create: .github/workflows/deploy.yaml
Section titled “Create: .github/workflows/deploy.yaml”Main deployment workflow:
- Trigger:
workflow_dispatchduring development; switches toworkflow_runonci.yamlsuccess onmainat cutover - Matrix over partitions with
max-parallel: 1for sequential deployment- During development on
demobranch: matrix is[demo] - After cutover on
main: matrix is[dev, stage, demo, prod]
- During development on
- Each matrix entry:
- Sets
environment: ${{ matrix.purpose }}for authorization gates - Calls
reusable_deployment.yamlwith the partition as input
- Sets
Create: .github/workflows/redeploy.yaml
Section titled “Create: .github/workflows/redeploy.yaml”Manual redeploy workflow:
- Trigger:
workflow_dispatchwith inputspartition(choice: dev/stage/demo/prod) andcommit_sha(string) - Single partition, no matrix
- Verifies CI passed for the SHA (commit status API); runs CI inline if not
- Calls
reusable_deployment.yamlwith the partition and commit SHA - Uses
environment: ${{ inputs.partition }}for authorization gates
Create: .github/workflows/reusable_deployment.yaml
Section titled “Create: .github/workflows/reusable_deployment.yaml”Reusable workflow called by both deploy.yaml and redeploy.yaml:
- Inputs:
partition(string),commit_sha(string, optional — defaults to HEAD of connected branch) - Sets
environment: ${{ inputs.partition }} - Permissions:
contents: read,id-token: write - Steps:
- Fetch purpose-configuration for the partition using
Arda-cards/purpose-configuration-action→ getaws_role,aws_region - Derive the frontend role ARN: append
FrontEndto the role name inaws_role(e.g.,Alpha001-API-GitHubAction→Alpha001-API-GitHubActionFrontEnd) - Parse the infrastructure prefix from the role name (text before
-API-GitHubAction, e.g.,Alpha001) - Configure AWS credentials via OIDC using the derived frontend role ARN
- Read CloudFormation exports:
${Infrastructure}-${Partition}-I-AmplifyAppIdand${Infrastructure}-${Partition}-I-AmplifyBranchName - Call
aws amplify start-job --app-id {AmplifyAppId} --branch-name {AmplifyBranchName} --job-type RELEASE(with--commit-idifcommit_shais provided) - Poll
aws amplify get-jobuntil status isSUCCEEDorFAILED - Fail the workflow if the deployment fails
- Fetch purpose-configuration for the partition using
GitHub Settings: Create environments
Section titled “GitHub Settings: Create environments”dev: no protection rulesstage:required_reviewers— denisa, jmpicnic, danmerb, davequintaprod:required_reviewers— denisa, jmpicnic, danmerb, davequinta
Acceptance Criteria
Section titled “Acceptance Criteria”- All three workflow files exist on the
demobranch and pass YAML lint - Manually triggering
deploy.yamlon thedemobranch:- Fetches
demo.propertiesfrom purpose-configuration - Assumes the
Alpha001-API-GitHubActionFrontEndrole via OIDC - Calls
StartJobagainst the demo Amplify app - Polls
GetJobuntil the deployment completes - The Amplify build succeeds (Amplify runs
npm ci, resolves env vars, runsnpm run build, deploys)
- Fetches
- The site at
demo.app.arda.cardsis updated with the latest code from thedemobranch - GitHub environments are configured with the correct protection rules
- Triggering with a partition that has
required_reviewerspauses for approval
Verification
Section titled “Verification”- Trigger
deploy.yamlvia GitHub Actions UI on thedemobranch - In the workflow logs, confirm:
- Purpose-configuration fetch succeeded (check logged properties — not secret values)
- OIDC role assumption succeeded (
aws sts get-caller-identity) StartJobreturned ajobIdGetJobpolling shows status progressing toSUCCEED
- Visit
demo.app.arda.cardsand verify the page loads - Check the Amplify Console for the demo app: confirm the build was triggered by the
StartJobcall (not auto-build)
Step 4 — Validation
Section titled “Step 4 — Validation”Preconditions
Section titled “Preconditions”- Step 3 is complete: all three workflow files (
deploy.yaml,redeploy.yaml,reusable_deployment.yaml) exist on thedemobranch anddeploy.yamlhas successfully triggered at least one Amplify build. - The demo site at
demo.app.arda.cardsis accessible. - GitHub environments (
dev,stage,prod) are configured onarda-frontend-appwith the correct protection rules. - Test user credentials are available for signing in to the demo site (user performs the sign-in manually).
- The
demobranch has at least two distinct commits on it soredeploy.yamlcan be tested with an older SHA.
Purpose
Section titled “Purpose”Validate the full pipeline by deploying to the demo partition and verifying functional equivalence with the existing deployments. Test the redeploy workflow and CI check gate.
Repositories Affected
Section titled “Repositories Affected”arda-frontend-app(ondemobranch — no code changes, workflow triggers only)
Changes Needed
Section titled “Changes Needed”No code changes. This step is purely execution and verification.
Acceptance Criteria
Section titled “Acceptance Criteria”deploy.yamlsuccessfully deploys to the demo partition- The application at
demo.app.arda.cardsis functional:- Page loads without errors
- User can sign in with test credentials (user logs in manually)
- Navigation to Items, Order Queue, and other pages works
- No
NEXT_PUBLIC_*configuration errors in the browser console
redeploy.yamlsuccessfully deploys a specific commit SHA to the demo partition:- The deployed version matches the requested SHA (verify in the Amplify Console build log)
- The CI check gate works:
- Attempting to redeploy a SHA that has no CI status is handled correctly (CI runs inline, or the workflow aborts)
- The demo deployment does not affect any other partition (dev, stage, prod remain on their existing branch-sync deployments)
Verification
Section titled “Verification”- Trigger
deploy.yamlon thedemobranch, verify deployment succeeds - Visit
demo.app.arda.cards:- User signs in with test credentials
- Agent verifies page navigation via Playwright MCP or reusing existing E2E test patterns
- Trigger
redeploy.yamlwith a specific earlier commit SHA fromdemo:- Verify the Amplify Console shows the build used the specified commit
- Verify the site reflects the older version
- Redeploy the latest commit to restore current state
- Confirm dev/stage/prod sites are unchanged by checking their Amplify Console (no new builds triggered)
Step 5 — Production Cutover
Section titled “Step 5 — Production Cutover”Preconditions
Section titled “Preconditions”- Step 4 is complete: the demo pipeline is validated —
deploy.yamlandredeploy.yamlwork correctly against the demo partition, the CI check gate is functional, and the demo site is confirmed functional. - The
Alpha002-API-GitHubActionFrontEndIAM role exists in the Alpha002 account (deployed upfront in Step 2) and has been verified to be assumable from thearda-frontend-apprepository (test via a minimal workflow onmain, similar to the Step 2 OIDC test). - The existing Amplify app IDs for dev (
d38w5m1ngjza76), stage (d1kbrvra79y8sc), and prod (duhexavnwh88g) have been verified against the live AWS accounts viaaws amplify get-app --app-id {id}. - AWS CLI access to both Alpha001 and Alpha002 accounts is available for reconfiguring existing Amplify apps.
- The
rollback-plan.mdis written and reviewed before any changes to existing Amplify apps. - All stakeholders (denisa, jmpicnic, danmerb, davequinta) are aware of the cutover and available as reviewers for the
stageandprodenvironment gates.
Purpose
Section titled “Purpose”Migrate the existing Amplify apps (dev, stage, prod) to the new GitHub Actions pipeline. Disable the existing branch-sync auto-build, connect all apps to main, and perform the first full sequential deployment with authorization gates.
Repositories Affected
Section titled “Repositories Affected”arda-frontend-app(merge tomain)infrastructure(deploy lightweight export stacks; removedemofrom OIDC scope — follow-up)- Amplify app settings (AWS CLI — disable auto-build on existing apps)
Changes Needed
Section titled “Changes Needed”1. Create: rollback-plan.md (in the project working directory)
Section titled “1. Create: rollback-plan.md (in the project working directory)”Document manual rollback procedures before beginning the cutover:
- How to re-enable auto-build on each Amplify app:
aws amplify update-branch --app-id {id} --branch-name {branch} --enable-auto-build - How to trigger a manual build from the original branch:
aws amplify start-job --app-id {id} --branch-name {branch} --job-type RELEASE - How to redeploy a previous commit via
redeploy.yamlwith a known-good SHA - Contact list and escalation path
2. Deploy lightweight export stacks for existing apps
Section titled “2. Deploy lightweight export stacks for existing apps”The existing dev, stage, and prod Amplify apps were created manually and have no CloudFormation exports. Deploy the amplifyExports.cfn.yaml stack for each, using the known app IDs and the branch name mapping from amm.sh:
# Alpha002 — devaws cloudformation deploy \ --stack-name "Alpha002-dev-AmplifyExports" \ --template-file "src/main/cfn/amplifyExports.cfn.yaml" \ --parameter-overrides \ "Infrastructure=Alpha002" "Partition=dev" \ "AmplifyAppId=d38w5m1ngjza76" "AmplifyBranchName=dev"
# Alpha002 — stageaws cloudformation deploy \ --stack-name "Alpha002-stage-AmplifyExports" \ --template-file "src/main/cfn/amplifyExports.cfn.yaml" \ --parameter-overrides \ "Infrastructure=Alpha002" "Partition=stage" \ "AmplifyAppId=d1kbrvra79y8sc" "AmplifyBranchName=stage"
# Alpha001 — prodaws cloudformation deploy \ --stack-name "Alpha001-prod-AmplifyExports" \ --template-file "src/main/cfn/amplifyExports.cfn.yaml" \ --parameter-overrides \ "Infrastructure=Alpha001" "Partition=prod" \ "AmplifyAppId=duhexavnwh88g" "AmplifyBranchName=main"These are deployed via amm.sh (which reads the app IDs and branch names from its constants). The stacks can also be deployed locally with the correct AWS profile.
3. Migrate dev from auto-build to matrix deployment
Section titled “3. Migrate dev from auto-build to matrix deployment”Disable auto-build on the dev Amplify app and add it to the workflow matrix. This is the first partition migrated — verify it works before proceeding.
- Disable auto-build:
Terminal window aws amplify update-branch --app-id d38w5m1ngjza76 --branch-name dev --no-enable-auto-build - Modify
.github/workflows/deploy.yaml:- Switch trigger from
workflow_dispatchtoworkflow_runonci.yamlsuccess onmain(retainworkflow_dispatchas secondary trigger) - Update matrix from
[demo]to[dev, demo]
- Switch trigger from
- Verify: trigger
deploy.yamlviaworkflow_dispatchand confirmdevdeploys successfully atdev.alpha002.app.arda.cards
4. Migrate stage from auto-build to matrix deployment
Section titled “4. Migrate stage from auto-build to matrix deployment”- Disable auto-build:
Terminal window aws amplify update-branch --app-id d1kbrvra79y8sc --branch-name stage --no-enable-auto-build - Modify
.github/workflows/deploy.yaml:- Update matrix from
[dev, demo]to[dev, stage, demo]
- Update matrix from
- Verify: trigger
deploy.yamlviaworkflow_dispatchand confirmstagedeploys successfully (requires reviewer approval) atstage.alpha002.app.arda.cards
5. Migrate prod from auto-build to matrix deployment
Section titled “5. Migrate prod from auto-build to matrix deployment”- Disable auto-build:
Terminal window aws amplify update-branch --app-id duhexavnwh88g --branch-name main --no-enable-auto-build - Modify
.github/workflows/deploy.yaml:- Update matrix from
[dev, stage, demo]to[dev, stage, demo, prod]
- Update matrix from
6. Enable PR preview deployments on the dev app
Section titled “6. Enable PR preview deployments on the dev app”Enable Amplify’s built-in pull request preview feature on the dev Amplify app so developers get fast feedback on PRs before merge:
- Enable PR previews:
Terminal window aws amplify update-branch --app-id d38w5m1ngjza76 --branch-name dev --enable-pull-request-preview - Test: open a test PR against
main, verify Amplify builds and deploys to a preview URL, verify the preview URL is posted as a comment on the PR, verify sign-in works.
Note: No Cognito callback URL changes are needed. The application uses direct password authentication (USER_PASSWORD_AUTH), not an OAuth/OIDC authorization code flow — sign-in works via API calls regardless of the serving domain.
PR previews are Amplify-managed and build independently of GitHub Actions CI — they trigger immediately on PR open/push via a GitHub webhook. The Amplify build spec includes npm run test (Jest unit tests) before npm run build as a quality gate: if tests fail, the build fails and the preview is not deployed. Lint and e2e tests remain GitHub Actions-only and gate the merge to main, not the preview. Each push to the PR branch redeploys to the same preview URL. The preview is automatically deleted when the PR is closed or merged.
Modify: Amplify build spec — add unit tests
Section titled “Modify: Amplify build spec — add unit tests”Update the Amplify build spec (inline on the dev app, or via amplify.yml in the repository) to run Jest unit tests before the build:
build: commands: - npm run test - npm run buildThis applies to both PR preview builds and official StartJob deployments, since Amplify uses the same build spec for both. Unit tests running twice (in GitHub Actions CI and in Amplify) is acceptable — Jest tests add only seconds to the 3-5 minute Amplify build.
7. Modify: infrastructure/src/main/cdk/constructs/oam/gh-oidc-provider.ts (follow-up)
Section titled “7. Modify: infrastructure/src/main/cdk/constructs/oam/gh-oidc-provider.ts (follow-up)”Remove refs/heads/demo from the OIDC trust conditions. Deploy via amm.sh.
8. Create: “How to Develop in the Front End” guide
Section titled “8. Create: “How to Develop in the Front End” guide”Create documentation/src/content/docs/process/craft/implementation/frontend-development.md — a developer-facing guide that documents the new workflow. This is the primary reference for developers working on the frontend after the pipeline transition. It should cover:
- Development workflow: open a PR against
main→ Amplify PR preview deploys automatically → verify at preview URL → push updates → merge when ready - PR preview details: how to find the preview URL (Amplify comment on the PR), what backend it talks to (dev partition), what quality gate applies (unit tests in Amplify build spec), automatic cleanup on PR close/merge
- Production deployment pipeline: what happens after merge to
main— CI runs, then sequential deployment to dev → stage → demo → prod with authorization gates - Manual redeploy / rollback: how to use
redeploy.yamlto deploy a specific SHA to a single partition - Local development: existing
npm run devworkflow, environment variable setup,.env.localconfiguration - Environment map: which URLs correspond to which partitions, accounts, and purposes
9. Create: post-cutover-instructions.md (in the project working directory)
Section titled “9. Create: post-cutover-instructions.md (in the project working directory)”Document deferred procedures for the user to follow:
- Production verification procedure: Step-by-step instructions for the user to verify the
prodmigration is working correctly atlive.app.arda.cards— sign-in, page navigation, key workflows. This verification must be coordinated with notice to business stakeholders and customers, as it confirms the production site is now served by the new pipeline. validate-pr-source.ymlrelaxation sequence (three options: remove, two-step, invert)dev,stage, anddemobranch deletion inarda-frontend-appAlpha001-demo-AmplifyandAlpha001-demo-AmplifyBranchstack deletion (if demo becomes permanent, skip this)
Acceptance Criteria
Section titled “Acceptance Criteria”rollback-plan.mdexists and documents rollback procedures for each partition- Lightweight export stacks are deployed for dev, stage, and prod with correct
AmplifyAppIdandAmplifyBranchNamevalues - CloudFormation exports are available for all four partitions (demo from
amplify.cfn.yaml/amplifyBranch.cfn.yaml; dev/stage/prod fromamplifyExports.cfn.yaml) - Each partition was migrated incrementally and verified before proceeding to the next:
dev: auto-build disabled, matrix[dev, demo], deployment verified atdev.alpha002.app.arda.cardsstage: auto-build disabled, matrix[dev, stage, demo], deployment verified atstage.alpha002.app.arda.cards(with reviewer approval)prod: auto-build disabled, matrix[dev, stage, demo, prod]
deploy.yamltriggers automatically when CI succeeds onmain(and retainsworkflow_dispatchas secondary trigger)- The first full sequential deployment from
maindeploys successfully:dev(no gate) →stage(reviewer approval) →demo(no gate) →prod(reviewer approval) - All four sites are functional after deployment
- Rollback mechanism verified:
redeploy.yamlsuccessfully deploys a previous SHA todevas a dry-run - PR preview deployments work on the dev app: opening a PR triggers a preview build, the preview URL is posted on the PR, sign-in works, and the preview is deleted on PR close
- “How to Develop in the Front End” guide exists at
documentation/src/content/docs/process/craft/implementation/frontend-development.md post-cutover-instructions.mdexists with deferred cleanup procedures
Relevant decisions: C2 (Alpha002 role upfront), C3 (no CloudFormation management of existing apps), C4 (matrix includes demo), C5 (branches deleted after stable), C6 (reusable workflows only), D5 (matrix hardcoded, changed at merge), D6 (Amplify branch names unchanged).
Verification
Section titled “Verification”- Verify rollback plan: review
rollback-plan.md; testaws amplify update-branch --enable-auto-buildon a non-production partition - Verify exports: for each partition,
aws cloudformation list-exports --query "Exports[?Name=='${Infra}-${Part}-I-AmplifyAppId'].Value"returns the correct app ID - Verify auto-build disabled: for each app,
aws amplify get-branch --app-id {id} --branch-name {branch} --query "branch.enableAutoBuild"returnsfalse - Merge a PR to
mainand confirmci.yamlruns, thendeploy.yamltriggers viaworkflow_run - Monitor the sequential deployment:
devauto-deploys,stagewaits for approval,demoauto-deploys,prodwaits for approval - After
proddeployment, visitlive.app.arda.cardsand verify:- Page loads, authentication works, API calls succeed
- The deployed version matches the merged commit SHA
- Rollback dry-run: use
redeploy.yamlto deploy the previous production SHA todevas a test of the rollback mechanism - PR preview: open a test PR against
main, verify:- Amplify builds the PR branch and deploys to a preview URL
- The preview URL is posted as a comment on the GitHub PR
- The preview site loads and sign-in works (direct password auth, no callback URL needed)
- Pushing a new commit to the PR branch redeploys to the same URL
- Closing the PR deletes the preview deployment
Open Questions
Section titled “Open Questions”| Id | Step | Question | Decision |
|---|---|---|---|
| D1 | 1 | amm.sh gate update strategy: The gate currently blocks both Alpha001 and Alpha002. For Step 1 we only need Alpha001/demo. Should we (a) allow all Alpha001 partitions (risks accidentally deploying Amplify to prod), (b) allow only demo on Alpha001 (more conditional logic), or (c) remove the gate entirely and parameterize Repo/AppName per infrastructure/partition (cleanest long-term, larger change)? | Gate should check a list of (Infrastructure, Partition) pairs that should be deployed. They should only include the Kyle Infra + Partition and (Alpha001, demo). The list should be a constant in amm.sh. |
| D2 | 1 | amm.sh Repo/AppName parameterization: Currently hardcoded to kyle-frontend-app. For Alpha001/demo it must be arda-frontend-app. How should this be parameterized — a case statement on ${infrastructure}, an environment variable, or a parameter read from purpose-configuration? | Explicit mapping constant in amm.sh, keyed by (Infrastructure, Partition). No new properties in purpose-configuration — all additional mappings (Repo, AppName, branch names, app IDs, regions) are maintained as constants in amm.sh. |
| D3 | 1 | amm.yml workflow secrets: The workflow passes Kyle/Stage-specific secrets (ARDA_API_KEY_KYLE, HUBSPOT_CLIENT_KEY_STAGE, etc.) for the partitionSecrets CloudFormation step. For Alpha001/demo, these values may be wrong. Should the workflow be updated with per-environment secret selection (similar to the backend’s secrets[format('KEY_{0}', matrix.purpose)] pattern), or should Step 1 be deployed locally to sidestep this? | Update the workflow to use secrets[format('ARDA_API_KEY_{0}', partition)] — per-environment API key secrets already exist as GitHub org secrets (see infrastructure/tools/sync-secrets-from-1password.sh). The other four secrets (signup, hubspot, pylon) are shared across environments and can remain as-is. |
| D4 | 1 | EnableAutoBuild parameter type: CloudFormation AWS::Amplify::Branch expects EnableAutoBuild as a boolean, but CloudFormation parameters don’t support boolean types. Should we use String with AllowedValues: ["true", "false"] and then !Equals condition, or is there a simpler pattern used elsewhere in this codebase? | Use a String with those allowed values. |
| D5 | 3 | Workflow on demo branch with [demo] matrix: The deploy.yaml workflow on the demo branch needs a [demo] matrix. After cutover on main it becomes [dev, stage, demo, prod]. Should this be (a) a workflow_dispatch input with a default, (b) hardcoded and changed at merge time, or (c) derived from the branch name? | (b) |
| D6 | 5 | Branch connection change for existing apps: At cutover, existing apps (connected to dev/stage/main branches) must be reconnected to main. StartJob uses the branchName parameter to identify the Amplify branch resource, not the git branch. The workflow reads the branch name from CloudFormation exports (AmplifyBranchName), so it always uses the correct Amplify branch resource name regardless of which git branch is connected. | Amplify Branch names remain unchanged throughout this migration. The branch name mapping in amm.sh and CloudFormation exports handle the partition→branch-name indirection uniformly. |
Copyright: © Arda Systems 2025-2026, All rights reserved