# Runbook — Deploy

Promote a build to staging or production.

## Audience

Anyone with deploy permission. Production deploy is gated by a manual `when: manual` step in GitLab CI.

## When to use

- Merge to `main` → staging deploys automatically.
- Tag `vX.Y.Z` + manual approval → production deploys.

## Pre-checks

- [ ] `/prepare-deploy <env>` returned **GO**.
- [ ] Latest CI run on the target ref is green.
- [ ] Migrations committed + reviewed.
- [ ] Release notes drafted (production only).
- [ ] Rollback path confirmed (`rollback.md`).
- [ ] No active incident on the target env.

## Steps — staging (auto)

1. Merge MR to `main` after review.
2. CI runs `validate → build → test → security → package → deploy:staging`.
3. Confirm pods healthy: `kubectl -n loma-portal-staging get pods`.
4. Smoke test:
   ```bash
   curl https://staging.loma-portal.example/api/health/ready
   ```
5. Optional manual smoke through the UI.

## Steps — production (manual)

1. Tag a release via `/release <bump>` (creates `vX.Y.Z` locally).
2. Push the tag → CI runs `package → deploy:production` (gated manual).
3. Open the GitLab `deploy:production` job; review the diff; click **Play**.
4. Helm applies with `--atomic --timeout 10m` — rollback automatically on failure.
5. Verify:
   ```bash
   kubectl -n loma-portal get pods
   kubectl -n loma-portal get hpa
   curl https://portal.loma-group.example/api/health/ready
   ```
6. Watch dashboards for 30 min (HTTP p95, error rate, queue depth).
7. Announce in `#releases` (Slack/LINE/Teams).

## Verification

| Check           | Expected                  |
| --------------- | ------------------------- |
| All pods Ready  | `kubectl get pods` clean  |
| `/health/ready` | 200                       |
| p95 latency     | < 300 ms within 5 min     |
| Error rate      | < 0.5% within 5 min       |
| Queue depth     | not growing without bound |

## Rollback

Helm rolls back automatically on `--atomic` failure. Manual rollback:

```bash
helm rollback loma-portal <revision> --namespace loma-portal
```

See [`rollback.md`](rollback.md) for the full procedure including DB considerations.

## Escalation

If anything looks off:

- Page the on-call.
- Run [`incident-orchestrator`](../../.claude/orchestrators/incident-orchestrator.md).
- Don't deploy another change until the current one is understood.
