Skip to content

Deployed Dev Environment

The deployed dev environment is Wavemap’s shared cloud-backed validation target. It is production-like where that gives release confidence, but it remains cost-first, disposable by default, and intentionally smaller than a future staging or production environment.

Local development and deployed dev are different trust boundaries. Local .env.dev files, local Docker, emulator credentials, and personal profiles are developer-machine inputs. Deployed dev values come from GitHub environment configuration, Pulumi stack config and outputs, AWS runtime stores, and deploy-time renderers.

SurfaceCurrent Decision
Cloud providerAWS is the first implemented provider.
Pulumi stackaws-dev; routine CD reads deployment contracts, while infra operators use the Pulumi backend.
Runtime regionus-east-2 for regional runtime resources.
Public app URLhttps://dev.wavemap.app.
Runtime targetSleepable EC2 host running Docker Compose.
Runtime containersFrontend, backend API, and Postgres.
DatabaseContainerized Postgres on the runtime host, disposable and reseedable for dev.
Media storagePrivate S3 bucket, with browser-facing media served through same-origin CloudFront /media/*.
RegistryPrivate ECR repositories for backend and frontend deploy images.
Operator accessSSM Session Manager. No routine SSH ingress.
Docs siteIndependent static surface at https://docs.wavemap.app; not served by this runtime.

The runtime host starts from Amazon Linux 2023, installs Docker during bootstrap, and keeps application release state under /opt/wavemap. Pulumi owns the host, security group, IAM role, deployment command document, and output contract. The deploy workflow owns image selection, env rendering, Compose updates, container restart, smoke checks, and runtime release receipts.

For command contracts, wrapper paths, key flags, and default mutation posture, use the Deploy Dev and Smoke sections of the CLI command reference.

Deployed dev should choose the lowest-cost shape that still preserves useful deployment confidence and acceptable demo UX. The current t3a.medium runtime host is an explicit exception to the smallest-host instinct because the frontend, backend, Postgres, Docker, and smoke checks share one VM.

The environment uses a sleepable-host model:

  • CloudFront remains the stable public app front door.
  • The EC2 runtime host can stop when idle.
  • A wake path starts the host and refreshes the dynamic origin when someone returns.
  • A shutdown Lambda owns deliberate host stop.
  • An inactivity monitor can invoke that same shutdown path after request inactivity.

Host stop is cost control. It is not data cleanup, database reset, media cleanup, backup, or stack teardown.

SourceOwnsNotes
GitHub dev environment variablesNon-secret workflow bootstrap values.Examples include selected provider, deployment environment, or Pulumi stack selectors.
GitHub dev environment secretsDeploy-time credentials or role ARNs.App runtime secrets should not be mirrored here unless explicitly documented as a temporary bridge.
Pulumi stack configInfrastructure choices and Pulumi-owned secrets.Use Pulumi secrets only for values that belong to infrastructure state.
Deployment contractSanitized non-secret deployment facts.Routine deploy commands consume registry URLs, runtime host paths, ingress facts, and explicit SSM executor handles here.
Pulumi outputsInfra-operator source facts.Approved outputs are projected into the deployment contract rather than read directly by routine CD.
AWS SSM Parameter StoreApp runtime config and runtime secrets.Preferred runtime store for /wavemap/dev/runtime/* values.
EC2 rendered env filesContainer process environment.Generated during deploy; never committed.
Docker build argsBrowser-visible frontend build values.NEXT_PUBLIC_* values are public and must not be treated as secrets.

Before adding, renaming, or removing environment variables, runtime config, build inputs, secrets, deployment contract fields, Pulumi outputs, or runtime parameters, follow Configuration And Secrets.

Runtime config does not currently need a dedicated operations page. The stable material is intentionally split by ownership:

HomeOwns
Configuration And SecretsCross-cutting source classification, visibility, secret handling, and verification rules.
This pageCurrent deployed-dev value ownership, runtime store, and environment shape.
Runtime Config ReadinessRepeated operator procedure for planning, populating, and checking runtime config readiness.
Deployment WorkflowsCD ordering, cloud-plan checks, deploy-time secret boundary, and runtime host handoff.

Create a dedicated operations page only when the operator surface outgrows the runbook, such as multi-environment runtime config promotion, routine rotation procedures, or a larger SSM inventory lifecycle.

The deployed-dev data posture is intentionally modest. Different operations have different data consequences:

  • Container restart and Compose restart should preserve the Postgres host path when that path is untouched.
  • EC2 stop/start should preserve the root EBS volume and therefore the current Postgres host path.
  • Destructive database reset is explicit and should not be hidden behind standby or host shutdown.
  • Media objects persist across host stop/start.
  • Media objects can become application-orphaned after destructive database reset.
  • The media bucket is disposable at the infrastructure lifecycle level; replacement or stack teardown can delete objects.
  • Backup/restore is a learning drill for this environment, not a production disaster-recovery guarantee.

Use Deployed Dev Lifecycle for the detailed lifecycle matrix, standby/teardown gradations, and expected evidence. Use Data Durability And Recovery for reset, media drift, backup learning-drill, and later-environment recovery gates. The reviewed operator procedures live in Runbooks.

The deployed-dev control plane is intentionally small:

  • CloudFront terminates public TLS for dev.wavemap.app.
  • Ordinary app traffic routes to the dynamic origin app-origin.dev.wavemap.app.
  • The static cold-start origin serves a Wavemap loading page while the runtime host is stopped or warming up.
  • The /__wake route starts the runtime host through a Lambda Function URL guarded by a CloudFront origin header.
  • The shutdown Lambda is invoked through AWS IAM only; it has no public route.
  • The inactivity monitor reads CloudFront request activity and invokes the shutdown Lambda after the configured quiet window.

The wake, shutdown, and inactivity Lambdas do not own app release state, database reset, backup, media cleanup, or stack teardown.

These actions remain explicit human decisions:

  • Pulumi preview/update for shared environment infrastructure.
  • IAM, OIDC trust, DNS, certificate, or deploy-role changes.
  • Runtime database reset.
  • Cold-start browser smoke that deliberately stops the shared runtime host.
  • Stack teardown or replacement of persistent/data-bearing resources.

Routine app/API CD can deploy new SHA-tagged images and run endpoint smoke. It should not silently widen into infrastructure mutation or data lifecycle work.