Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/deploy-hub.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Deploy Hub
on:
push:
branches: [main, dev]
branches: [main, dev, staging]
paths:
- "crates/ahand-hub/**"
- "crates/ahand-hub-core/**"
Expand All @@ -10,6 +10,8 @@ on:
- "proto/**"
- "Cargo.lock"
- "deploy/hub/Dockerfile"
- "deploy/hub/deploy.sh"
- "deploy/hub/task-definition.template.json"
- ".github/workflows/deploy-hub.yml"

permissions:
Expand All @@ -32,6 +34,10 @@ jobs:
echo "ENV=prod" >> "$GITHUB_ENV"
echo "ECS_CLUSTER=openclaw-hive" >> "$GITHUB_ENV"
echo "SERVICE_NAME=ahand-hub-prod" >> "$GITHUB_ENV"
elif [ "${{ github.ref }}" = "refs/heads/staging" ]; then
echo "ENV=staging" >> "$GITHUB_ENV"
echo "ECS_CLUSTER=openclaw-hive-dev" >> "$GITHUB_ENV"
echo "SERVICE_NAME=ahand-hub-staging" >> "$GITHUB_ENV"
else
echo "ENV=dev" >> "$GITHUB_ENV"
echo "ECS_CLUSTER=openclaw-hive-dev" >> "$GITHUB_ENV"
Expand Down
28 changes: 18 additions & 10 deletions deploy/hub/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

ENV="${1:-}"
[[ "$ENV" == "dev" || "$ENV" == "prod" ]] || { echo "Usage: $0 {dev|prod}"; exit 1; }
[[ "$ENV" == "dev" || "$ENV" == "staging" || "$ENV" == "prod" ]] || { echo "Usage: $0 {dev|staging|prod}"; exit 1; }

AWS_REGION="us-east-1"
ACCOUNT_ID="149614785083"
ECR_REGISTRY="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
ECR_REPO="ahand-hub"
GIT_SHA="${GIT_SHA:-$(git rev-parse --short HEAD)}"

if [[ "$ENV" == "prod" ]]; then
ECS_CLUSTER="openclaw-hive"
SERVICE_NAME="ahand-hub-prod"
API_DOMAIN="ahand-hub.team9.ai"
else
ECS_CLUSTER="openclaw-hive-dev"
SERVICE_NAME="ahand-hub-dev"
API_DOMAIN="ahand-hub.dev.team9.ai"
fi
case "$ENV" in
prod)
ECS_CLUSTER="openclaw-hive"
SERVICE_NAME="ahand-hub-prod"
API_DOMAIN="ahand-hub.team9.ai"
;;
staging)
ECS_CLUSTER="openclaw-hive-dev"
SERVICE_NAME="ahand-hub-staging"
API_DOMAIN="ahand-hub.staging.team9.ai"
;;
dev)
ECS_CLUSTER="openclaw-hive-dev"
SERVICE_NAME="ahand-hub-dev"
API_DOMAIN="ahand-hub.dev.team9.ai"
;;
esac

ECR_IMAGE="${ECR_REGISTRY}/${ECR_REPO}:${ENV}"
SSM_PREFIX="arn:aws:ssm:${AWS_REGION}:${ACCOUNT_ID}:parameter/ahand-hub/${ENV}"
Expand Down
172 changes: 172 additions & 0 deletions docs/superpowers/plans/2026-06-21-aws-t9-staging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# AWS t9 Staging Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add a first-class AWS t9 staging environment for the aHand hub.

**Architecture:** Reuse the existing `ahand-hub` Terraform module with a new
`infra/envs/staging` stack, and extend the global hub deploy workflow and deploy
script to map the `staging` branch to `ahand-hub-staging`.

**Tech Stack:** Terraform, AWS ECS/Fargate, SSM Parameter Store, GitHub Actions,
Bash.

---

### Task 1: Add A Staging Config Guard

**Files:**
- Create: `scripts/verify-aws-staging-config.sh`

- [ ] **Step 1: Write the failing guard script**

Create `scripts/verify-aws-staging-config.sh` with checks for:

- `infra/envs/staging/main.tf`
- module env validation containing `staging`
- `.github/workflows/deploy-hub.yml` triggering on `staging`
- deploy script accepting and mapping `staging`

- [ ] **Step 2: Run the guard and confirm it fails**

Run: `bash scripts/verify-aws-staging-config.sh`

Expected before implementation: non-zero exit and a missing staging message.

- [ ] **Step 3: Commit the guard**

Run:

```bash
git add scripts/verify-aws-staging-config.sh docs/superpowers/specs/2026-06-21-aws-t9-staging-design.md docs/superpowers/plans/2026-06-21-aws-t9-staging.md
git commit -m "docs: plan aws t9 staging environment"
```

### Task 2: Add Terraform Staging Stack

**Files:**
- Create: `infra/envs/staging/backend.tf`
- Create: `infra/envs/staging/main.tf`
- Create: `infra/envs/staging/providers.tf`
- Create: `infra/envs/staging/variables.tf`
- Create: `infra/envs/staging/versions.tf`
- Modify: `infra/modules/ahand-hub/variables.tf`

- [ ] **Step 1: Add `staging` to module env validation**

Update the validation list from `["prod", "dev"]` to
`["prod", "dev", "staging"]`.

- [ ] **Step 2: Copy the dev stack shape into staging**

Use the same t9 VPC, subnet, Traefik, and RDS values as dev. Set:

- backend key `ahand-hub/envs/staging/terraform.tfstate`
- default tag `Environment = "staging"`
- module `env = "staging"`
- `ecs_cluster_name = "openclaw-hive-dev"`
- `api_domain = "ahand-hub.staging.team9.ai"`
- `gateway_public_url = "https://api.staging.team9.ai"`

- [ ] **Step 3: Run Terraform validation**

Run:

```bash
terraform fmt -check infra/modules/ahand-hub infra/envs/dev infra/envs/staging
terraform -chdir=infra/envs/staging init -backend=false
terraform -chdir=infra/envs/staging validate
```

Expected: all commands exit 0.

- [ ] **Step 4: Commit Terraform changes**

Run:

```bash
git add infra/envs/staging infra/modules/ahand-hub/variables.tf
git commit -m "infra: add t9 staging hub stack"
```

### Task 3: Wire Staging Deployment

**Files:**
- Modify: `.github/workflows/deploy-hub.yml`
- Modify: `deploy/hub/deploy.sh`
- Modify: `infra/README.md`

- [ ] **Step 1: Extend branch mapping**

Add `staging` to the workflow branch trigger and determine-env block.

- [ ] **Step 2: Extend deploy script**

Allow `staging` and set:

- `ECS_CLUSTER=openclaw-hive-dev`
- `SERVICE_NAME=ahand-hub-staging`
- `API_DOMAIN=ahand-hub.staging.team9.ai`

- [ ] **Step 3: Update runbook**

Document prod/dev/staging, t9 profile/account, staging DNS, state key, and
deploy command.

- [ ] **Step 4: Validate**

Run:

```bash
bash scripts/verify-aws-staging-config.sh
ruby -e 'require "yaml"; YAML.load_file(".github/workflows/deploy-hub.yml"); puts "yaml ok"'
bash -n deploy/hub/deploy.sh
```

Expected: all commands exit 0.

- [ ] **Step 5: Commit deploy wiring**

Run:

```bash
git add .github/workflows/deploy-hub.yml deploy/hub/deploy.sh infra/README.md scripts/verify-aws-staging-config.sh
git commit -m "ci: deploy hub staging on aws t9"
```

### Task 4: Live AWS Staging Bring-Up

**Files:**
- No source changes expected unless validation reveals missing config.

- [ ] **Step 1: Inspect Terraform plan**

Run:

```bash
terraform -chdir=infra/envs/staging init
terraform -chdir=infra/envs/staging plan
```

Expected: planned resources are isolated to `ahand-hub-staging` and
`/ahand-hub/staging/*`.

- [ ] **Step 2: Apply after plan review**

Run: `terraform -chdir=infra/envs/staging apply`

- [ ] **Step 3: Seed runtime secrets**

Write real values for:

- `/ahand-hub/staging/DATABASE_URL`
- `/ahand-hub/staging/SENTRY_DSN`

- [ ] **Step 4: Deploy staging image**

Push the branch and let the `staging` branch deploy, or run
`./deploy/hub/deploy.sh staging` after pushing an image tagged `staging`.

- [ ] **Step 5: Verify live service**

Run AWS ECS checks and `curl -fsS https://ahand-hub.staging.team9.ai/api/health`.
92 changes: 92 additions & 0 deletions docs/superpowers/specs/2026-06-21-aws-t9-staging-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# AWS t9 Staging Environment Design

## Goal

Add a first-class AWS t9 staging environment for the aHand hub, matching the
existing global AWS deployment path instead of only relying on the Qisi staging
runtime.

## Scope

This change covers the Rust hub service deployed by `.github/workflows/deploy-hub.yml`.
The global AWS path does not currently deploy the Next.js hub dashboard
container, so dashboard Sentry/runtime settings remain Qisi-only until a global
dashboard deployment path exists.

## Environment Mapping

The GitHub branch mapping should be:

| Branch | Environment | ECS cluster | ECS service | Public host |
|---|---|---|---|---|
| `main` | `prod` | `openclaw-hive` | `ahand-hub-prod` | `ahand-hub.team9.ai` |
| `dev` | `dev` | `openclaw-hive-dev` | `ahand-hub-dev` | `ahand-hub.dev.team9.ai` |
| `staging` | `staging` | `openclaw-hive-dev` | `ahand-hub-staging` | `ahand-hub.staging.team9.ai` |

Staging uses the t9 account (`149614785083`), the non-production cluster
(`openclaw-hive-dev`), and a separate Terraform stack under
`infra/envs/staging`.

## Terraform

Add `infra/envs/staging` as an independent backend state:

- S3 backend bucket: `team9-tfstate`
- State key: `ahand-hub/envs/staging/terraform.tfstate`
- AWS profile: `t9`
- Lock table: `terraform-state-lock`

The staging stack should call `../../modules/ahand-hub` with:

- `env = "staging"`
- `ecs_cluster_name = "openclaw-hive-dev"`
- `api_domain = "ahand-hub.staging.team9.ai"`
- The same t9 VPC, subnet, Traefik, and RDS values used by dev
- `gateway_public_url = "https://api.staging.team9.ai"`
- `redis_mode = "create"`

The shared module's `env` validation must accept `staging`.

## Runtime Parameters

Terraform seeds `/ahand-hub/staging/*` parameters the same way as dev/prod.
Operator-seeded values remain out of Terraform state:

- `/ahand-hub/staging/DATABASE_URL`
- `/ahand-hub/staging/SENTRY_DSN`

`DATABASE_URL` must point at a dedicated `ahand_hub_staging` database/user in
the staging/non-production RDS instance before the service can run healthily.
`SENTRY_DSN` can be placeholder initially, but automatic Sentry capture is not
active until a real DSN is written and ECS is redeployed.

## CI/CD

`.github/workflows/deploy-hub.yml` should trigger on `staging` and set:

- `ENV=staging`
- `ECS_CLUSTER=openclaw-hive-dev`
- `SERVICE_NAME=ahand-hub-staging`

`deploy/hub/deploy.sh` should accept `staging`, select the same cluster/service,
and render `API_DOMAIN=ahand-hub.staging.team9.ai`.

## Validation

Local validation should include:

- A repo check proving staging is wired into Terraform, workflow, and deploy
script.
- YAML parse of `.github/workflows/deploy-hub.yml`.
- Bash syntax check of `deploy/hub/deploy.sh`.
- `terraform fmt -check` for shared module and env stacks.
- `terraform init -backend=false` and `terraform validate` for
`infra/envs/staging`.

Live validation after merge/apply should include:

- Terraform plan/apply for `infra/envs/staging` using profile `t9`.
- SSM presence checks for `/ahand-hub/staging/*`.
- ECS service check for `ahand-hub-staging`.
- Staging deploy run from the `staging` branch.
- Health check at `https://ahand-hub.staging.team9.ai/api/health`.
Loading
Loading