# Deployment

ows-coda is deployed via **Jenkins → Docker → ECR → Fargate** in `us-east-1`. The pipeline is defined in `Jenkinsfile` at the repo root.

## Pipeline stages

```mermaid
flowchart LR
    push[Push to branch] --> checks[Checks & Static Tests]
    checks --> decision{master?}
    decision -- No --> done[Done - PR checks only]
    decision -- Yes --> release[Create Release]
    release --> scan[Scan Docker Image]
    scan --> deploy[Deploy to QA]
```

### 1. Checks & Static Tests (all branches)

Runs in parallel on every push and PR:

- **Compliance checks** — internal policy validation
- **Software catalog validation** — Datadog catalog definition
- **SAST** — static application security tests
- **Sonar scan** — code quality analysis
- **Unit tests & style checks** — `docker compose up lint-and-test` (runs `pnpm test` = ESLint + Vitest with coverage)

### 2. Create Release (master only)

Builds the `deploy` Docker target and pushes to ECR:

- ECR account: `989790945997`
- Image tag: git commit SHA
- Requires `GITHUB_NPM_TOKEN` build secret for private npm packages

Also triggered on PRs with the `build docker` label or comment.

### 3. Scan Docker Image (master only)

Container vulnerability scanning against the pushed image. Currently **non-blocking** (`failBuild: false`).

### 4. Deploy to QA (master only)

Auto-deploys to QA via Fargate:

- AWS account: `989790945997`
- Role: `qa-jenkins-pipeline-deploy-role`
- Region: `us-east-1`

## Docker build stages

| Stage             | Purpose                                                                                                     |
| ----------------- | ----------------------------------------------------------------------------------------------------------- |
| `prod-deps`       | Install production-only dependencies                                                                        |
| `dev-deps`        | Install all dependencies + copy source                                                                      |
| `lint-and-test`   | Run `pnpm test` (used by CI)                                                                                |
| `build-artifacts` | Compile TypeScript server                                                                                   |
| `client-build`    | Build React client with Vite                                                                                |
| `deploy-server`   | Production server only — no frontend static files                                                           |
| `deploy-local`    | Full stack for local Docker dev — server + Docker-built client                                              |
| `deploy`          | Full stack for CI — server + pre-built client (passed as additional Docker build context via suiteAppBuild) |

## Search service deployment

The search service (`apps/search/`) is deployed as a separate Fargate service with its own ECR repository (`ows-coda-search`). It runs on port 8081 and is accessed by the main server via ConnectRPC (internal VPC traffic only).

- ECR repo: `terraform-infra/shared/prod/ecr/repos/ows-coda-search/`
- Service infra: `terraform-infra/qa/ows-coda/` (search service definition)
- Separate Docker build from the same monorepo, targeting the search service

## Environment promotion

| Environment    | Trigger                    | Notes                                                   |
| -------------- | -------------------------- | ------------------------------------------------------- |
| **Local**      | Manual (`pnpm dev`)        | Points to QA backends by default (via `.env`)           |
| **QA**         | Auto on merge to `master`  | Fargate in `989790945997`, auto-deployed by Jenkins     |
| **Production** | Manual / separate pipeline | Requires separate deploy step (not in this Jenkinsfile) |

## Notifications

- **Slack** — build regressions and fixes on `master` post to `#abacus-devs`
- **Retrigger** — comment `retest this please` on a PR to re-run the pipeline

## Rollback

If a QA deployment introduces a regression:

1. **Identify the last good commit SHA** from the ECR image tags or Jenkins build history
2. **Redeploy the previous image:**
   ```bash
   # Via Jenkins: re-run the deploy stage of the last good build
   # Or manually via AWS CLI:
   aws ecs update-service --cluster qa-ows-coda --service qa-ows-coda \
     --force-new-deployment --task-definition qa-ows-coda:<previous-revision>
   ```
3. **If a database migration was included**, check whether it's backwards-compatible. Most Prisma migrations add columns/tables and are safe to roll back the application without rolling back the migration. Destructive migrations (column drops, renames) require manual intervention.

Production rollback follows the same pattern but requires the production deploy role and cluster.

## Ephemeral environments

PR-triggered ephemeral environments are available for pre-merge testing. Comment on a PR to manage:

```
ephemeral deploy       # create environment (default 7-day TTL)
ephemeral deploy 15d   # create with custom TTL
ephemeral destroy      # tear down
ephemeral list         # show all active environments
```

Each environment gets its own Fargate service and MySQL schema on shared QA infrastructure. See [Ephemeral Environments](ephemeral-environments.md) for the full guide and [Ephemeral Environments TRD](../decisions/trds/ephemeral-environments.md) for the technical design.

## Troubleshooting deployments

| Issue                                    | Cause                                      | Fix                                                                                 |
| ---------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------- |
| `GITHUB_NPM_TOKEN` error in Docker build | Token not set or expired                   | Regenerate PAT with `read:packages` scope, set in environment                       |
| ECR push fails                           | Not authenticated                          | Run `pnpm docker:login` or `aws ecr get-login-password`                             |
| Fargate task fails health check          | App crash on startup                       | Check CloudWatch logs for the task; common causes: missing env vars, DB unreachable |
| Client assets 404 in QA                  | suiteAppBuild failed or context not passed | Check Jenkins build log for client build stage                                      |
| Deployment stuck (ECS draining)          | Old tasks not stopping                     | Check ECS console for task status; force new deployment if stuck                    |

## Useful commands

```bash
docker buildx bake     # build deploy images
pnpm docker:up        # build + run on :8080
pnpm docker:test:unit # lint + test in container
pnpm docker:clean     # tear down everything
pnpm docker:login     # authenticate to both ECR registries
```
