CI/CD & Environments

This guide covers the deployment pipeline, environment types, and automation workflows.

Environments

The monorepo supports three environment types:

Type Name Pattern Purpose Lifecycle
Production production Live user-facing environment Manual deploy via workflow_dispatch
Integration integration Staging / continuous integration Auto-deploys on merge to main
Ephemeral pr0001pr9999 Per-PR preview environments Auto-created on PR, destroyed on close

Environment Differences

Aspect Production Integration Ephemeral
DynamoDB removal RETAIN DESTROY DESTROY
Log retention 1 year 2 weeks 2 weeks
Lambda minification Yes No No
Source maps No Yes Yes
Self-signup No No Yes
SSO sign-in Yes Yes No
Assets bucket Yes Yes No
Data seeding From integration, minus studio content
Docs publishing Yes (canonical) Yes (staging preview) No

CI/CD Workflows

Deployment Workflows

Workflow Trigger Environment
deploy-integration.yml Push to main integration
deploy-production.yml Manual (workflow_dispatch) production
deploy-ephemeral.yml PR opened/updated ephemeral (per-PR)
destroy-ephemeral.yml PR closed; manual workflow_dispatch Destroys ephemeral stack

Verification Workflow (verify.yml)

Runs on every PR (ready for review / synchronize):

  1. Lintpnpm check --affected (lint + type-check across affected workspaces)
  2. Backend Testspnpm run test in apps/backend (with coverage)
  3. Check PR conventions — Validates conventional commit subjects and the pull request title

Deployment Pipeline (base-deploy.yml)

The reusable deployment workflow runs these jobs:

frontend-build ──┐
                  ├──► frontend-upload
infrastructure ──┘

     └──► publish-docs (production + integration only)
  1. frontend-build — Installs deps, builds Vite app, uploads artifact
  2. infrastructure — Runs the deploy orchestration script (see Deploy Orchestration below)
  3. frontend-upload — Downloads build artifact, syncs to S3, invalidates CloudFront
  4. publish-docs — Publishes Scalar documentation (production and integration only)

Docs Publishing: Documentation is published for production and integration only. Each environment has its own Scalar project and custom domain: production at docs.gamecraft.learnwith.ai, integration at docs-integration.gamecraft.rp.devfactory.com. The API reference automatically points to the environment's own API, so reviewers can test endpoints directly from the docs. Ephemeral (PR) environments do not publish docs.

Deploy Orchestration

The infrastructure job runs pnpm run deploy:<type> from apps/infra/, which invokes deploy.orchestrator.ts. This orchestrator runs the full deploy lifecycle in a single process:

  1. Seed reservations — provisions shared account-level resources (CloudFront origin request policies) and writes SSM reservations to protect them from concurrent cleanup
  2. Synth — runs cdk synth to produce the CloudFormation template (separate step because pre-deploy reads the synthesized template)
  3. Pre-deploy (pre-deploy.hook.ts) — imports orphaned CloudWatch log groups so CDK can adopt them
  4. CDK deploy — applies the CloudFormation changeset (Lambda, API Gateway, DynamoDB, Cognito, CloudFront)
  5. Post-deploy (post-deploy.hook.ts):
    • Publishes environment config JSON to S3 (used by frontend for environment switching)
    • Runs optional external integrations via the integration registry (e.g., Slack notifications, Datadog dashboard upserts)
    • Seeds ephemeral environments (copies Cognito users and the DynamoDB table from integration, excluding environment-bound studio content — games, chats, shares — and re-applies admin designations)
    • Seeds the API and E2E test users (ephemeral and integration; never production) and stores their credentials in SSM, where pnpm script update-env and the post-deploy test jobs pick them up

Persistence

All environments run on DynamoDB (PERSISTENCE=dynamodb). The Postgres code path (VPC-attached lambdas, migration runner, wseng-db-helper schema provisioning) is retained in the codebase but not wired: it depended on the shared dev Postgres cluster in the old WS.Eng account (856284715153), which is not reachable from the current deployment accounts. Re-enabling it requires provisioning a database and passing vpcId/securityGroupId/dbHost in apps/infra/app.ts.

Destroy Orchestration

When a PR is closed, destroy-ephemeral.yml runs pnpm run destroy:ephemeral from apps/infra/, which invokes destroy.orchestrator.ts. The same workflow also accepts manual workflow_dispatch for orphaned ephemeral stacks whose automatic destroy failed or never ran (for example, a closed PR whose stack still exists).

Manual dispatch must check out a fresh fixed ref (typically main at the current tip), not re-run an old failed workflow attempt. Destroy hooks evolve with the repo; replaying the code snapshot from the original PR-close run can miss pre-destroy teardown or grant assumptions that later commits fixed.

  1. Pre-destroy (pre-destroy.hook.ts): tears down hook-managed Studio AgentCore resources before CloudFormation deletes the stack:
    • Deletes the studio_<env> AgentCore runtime and its workload identity
    • Deletes the per-env studio execution role
    • Fail-closes: any failure aborts the orchestrator before cdk destroy (while the shared CI deploy role still holds the studio lifecycle grants)
  2. CDK destroy: tears down the CloudFormation stack
  3. Post-destroy (post-destroy.hook.ts): cleans up environment artifacts that outlive the stack:
    • Deletes S3 environment configs
    • Removes per-env SSM parameters (including the studio runtime ARN)
    • Cleans up orphaned CloudWatch log groups from CDK custom resources
    • Runs optional integration cleanup (e.g., revokes external resources registered by integrations)
    • Releases and sweeps SSM reservations for shared resources

Post-destroy is intentionally skipped when CDK destroy fails: the stack still exists, so cleaning up reservations or shared policies would be incorrect. On failure, the workflow opens a GitHub issue for manual intervention.

Studio deploy-role grant (non-ephemeral only)

StudioDeployRoleGrantConstruct is wired only on integration and production stacks. It attaches one inline policy with project-family wildcards to the shared GithubActionsOidcCdkDeployRole, covering every environment's studio-worker ECR repo and AgentCore execution-role family. Ephemeral stacks do not seed their own copy because multiple CloudFormation stacks must not claim policies on the same shared role.

Note: Manual API calls can be made via the Scalar interactive docs (/docs/viewer) or by running the auto-generated tests in packages/api-tests/.

Automation Workflows

Workflow Schedule Purpose
auto-update-branches.yml Every 30 min Keeps feature branches up-to-date with main
auto-release-accepted.yml Every 15 min Auto-releases accepted PRs
review-pr.yml On PR events Automated PR review

Deployment Flow (End-to-End)

A typical integration deployment follows this sequence:

  1. Developer merges a PR into main
  2. deploy-integration.yml triggers automatically
  3. It calls base-deploy.yml with environment: integration
  4. frontend-build compiles the React app with Vite
  5. infrastructure runs the deploy orchestration script (deploy:integration), which seeds account-level resources, synthesizes, runs pre-deploy hooks, deploys the CDK stack, and runs post-deploy hooks (environment config publish, integration sync)
  6. frontend-upload syncs the built assets to S3 and invalidates the CloudFront cache
  7. publish-docs generates and publishes Scalar documentation with the latest API spec

For PR environments, the same pipeline runs with environment: prNNNN (the environment type is derived automatically from the name), but the publish-docs job is skipped (docs are only published for production and integration).

Managing Environments

Syncing Local .env from a Deployed Environment

# From the integration environment
pnpm script update-env integration

# From a specific PR environment
pnpm script update-env 20

# Wait for a stack that is still deploying
pnpm script update-env integration --wait

The script auto-selects the AWS profile matching the target environment's account (--env/--pr flags remain supported).

Accessing Deployed Environments

Environment Frontend URL API URL Docs URL
Production https://gamecraft.learnwith.ai https://api.gamecraft.learnwith.ai https://docs.gamecraft.learnwith.ai
Integration https://integration.gamecraft.rp.devfactory.com https://api-integration.gamecraft.rp.devfactory.com https://docs-integration.gamecraft.rp.devfactory.com
Ephemeral https://prNNNN.gamecraft.rp.devfactory.com https://api-prNNNN.gamecraft.rp.devfactory.com

Ephemeral environment URLs are output by the deploy step and posted as a PR comment.