Skip to main content

Environment Strategy

Last updated: 2026-03-27 Decision owners: Joe, CC


Current State: Single Environment ("dev")

We run a single AWS environment that serves production traffic at app.nquiry.ai. It is named "dev" in all Terraform resources (invapp-dev-*) but is production in every functional sense:

  • Terraform environment: environments/dev/
  • Resource prefix: invapp-dev (cluster, service, ECR repo, ALB, RDS, etc.)
  • State backend: s3://invapp-terraform-state-760007728097 key dev/terraform.tfstate
  • Domain: app.nquiry.ai via Route53 + CloudFront + ALB
  • ECS: invapp-dev-cluster / invapp-dev-app-service (1 task, 512 CPU / 1024 MB)
  • RDS: invapp-dev-postgres, single-AZ, db.t3.micro, deletion protection ON
  • Redis: cache.t3.micro, single node
  • WAF: Bot control in count (log-only) mode
  • CloudTrail: Data events disabled (cost savings)
  • CloudFront Basic Auth: Currently enabled (pre-launch gate)

There is no staging environment. Local development runs via npm run dev against a local PostgreSQL instance (or tunneled RDS).

Why "dev" is actually prod

The naming is a historical artifact. When infrastructure was first provisioned, we started with "dev" expecting to add staging/prod later. Since we are a one-person team with no paying users yet, the single environment has been sufficient. All real data (test scenarios, demo investigations) lives here.


Gate 1: Rename dev to prod

Trigger: Before first paying customer or public launch.

What changes

  1. Create infrastructure/terraform/environments/prod/main.tf with identical module configuration
  2. Resource prefix becomes invapp-prod
  3. Migrate state: terraform state mv or fresh terraform import for all resources
  4. Update CI/CD env vars in GitHub Actions secrets:
    • ECR_REPOSITORY: invapp-dev-app -> invapp-prod-app
    • ECS_CLUSTER: invapp-dev-cluster -> invapp-prod-cluster
    • ECS_SERVICE: invapp-dev-app-service -> invapp-prod-app-service
  5. Update CloudFront Basic Auth: disable (enable_basic_auth = false)
  6. Consider enabling:
    • WAF bot control in block mode
    • CloudTrail data events
    • Multi-AZ RDS (enable_multi_az = true)
    • Larger instance sizes if load warrants

What stays the same

  • Single environment (no staging yet)
  • Same AWS account
  • Same domain (app.nquiry.ai)
  • Same deployment flow (push to main -> deploy)
  • Local dev unchanged (npm run dev)

What we explicitly skip

  • No staging environment (cost, complexity, team size)
  • No blue-green or canary deployments
  • No separate database for staging

Gate 2: Add Staging

Trigger: When real users are on the platform and we need a pre-prod validation gate (e.g., multiple team members, customer-impacting changes need soak testing).

What changes

  1. Create infrastructure/terraform/environments/staging/main.tf
  2. Resource prefix: invapp-staging
  3. Staging domain: staging.nquir.ai or similar
  4. Deployment flow becomes: main -> staging (auto) -> prod (manual promotion or auto after soak)
  5. Staging gets its own RDS, Redis, ECS cluster (smaller instances)
  6. Staging shares Cognito user pool or gets its own (TBD based on testing needs)

Cost estimate

Roughly doubles AWS spend. Current baseline is low (t3.micro everything), so staging would add ~$50-80/month for the minimal footprint.


Decision Rationale

FactorDecision
Team size1 developer + AI agents. No need for environment isolation between team members.
User basePre-launch. No paying customers yet. Downtime risk is acceptable.
CostEvery duplicated environment doubles infrastructure spend for no current benefit.
ComplexityManaging state across environments adds operational burden with no payoff at this scale.
SpeedSingle environment means faster iteration. No promotion gates to slow down shipping.

This is a deliberate, documented choice -- not an oversight. We will add environments when the risk/benefit equation changes.