Teu progresso
0 / 83 módulos0%
Estágio 03 · 03-04
BloqueadoCI/CD é onde projetos perdem mais tempo do que admitem. Pipelines de 30 min em projetos pequenos. Builds que falham flaky aleatoriamente. Deploy manual disfarçado de "automated" porque alguém precisa apertar botão. Rollback que demora 20 min. Secrets em logs. Branches sem proteção. Devs que esperam CI verde e empurram outra vez sem entender o que falhou.
Este módulo é CI/CD profissional: pipeline rápido (paralelizado, cached), deploys reprodutíveis, rollback em segundos, segurança (supply chain, secrets), padrões modernos (trunk-based, GitFlow, deploy strategies, feature flags). Você sai com pipeline que confia.
Continuous Deployment exige maturidade alta: testes confiáveis, observability forte, rollback automático, feature flags. Em projetos novos, comece em Continuous Delivery (deploy automático em staging, manual em prod) e suba.
Em 2026, GitHub Actions domina nos projetos open-source e médios. GitLab forte em enterprise self-hosted.
Estrutura típica:
PR opened → install → lint → typecheck → unit → integration → build → e2e → deploy preview
PR merge → install → lint → typecheck → unit → integration → build → e2e → deploy staging → smoke → deploy prod (gated) → notify
Ou separado por workflows.
Princípios:
node_modules ou ~/.pnpm..next/cache, dist/).docker/build-push-action com cache-from/cache-to em GHCR ou registry).GitHub Actions:
- uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
Restore parcial é problema sutil. Use restore-keys com prefix.
Rodar mesma suite em múltiplas combinações:
strategy:
matrix:
node: [20, 22]
os: [ubuntu-latest, macos-latest]
Útil pra libs cross-platform/cross-version. Em apps específicos a 1 stack, matrix é overhead.
DRY pra pipelines com múltiplos repos ou múltiplos jobs similares:
action.yml, agrupa steps..github/workflows/reusable.yml, called via uses:.Em monorepo: 1 workflow base parametrizado, jobs por package.
Nunca logue secrets. CI mascara automaticamente, mas evite echo $SECRET.
GitHub Settings:
Padrão: nada chega em main sem CI verde + revisão.
Em 2026, trunk-based + feature flags + deploys frequentes é dominante em SaaS. GitFlow ainda em projetos com binários distribuídos.
feat:, fix:, chore:): habilita auto-generation.Pra serviços (não publicados como pkg), versioning ainda importa pra rastreabilidade, tag git por release.
Ferramentas: Argo Rollouts, Flagger (K8s). Manual via Service mesh weights ou Ingress canary annotations (Nginx).
Decoupling deploy de release. "Ship dark", ativa quando pronto. Reverter sem redeploy.
Cuidado com tech debt de flags antigas. Monitore staleness.
Imutabilidade: tag com SHA do commit. Promoção de staging pra prod deve usar mesma image, não rebuild.
syft gera; CISA promove.Em 2026, supply chain virou regulado em algumas jurisdições. SBOM + signing é mainstream.
Monorepo (pnpm workspaces, Turborepo, Nx, Bazel) precisa skipar tarefas em packages não afetados:
affected:* commands.Em CI: detectar mudanças por path (paths-filter) e disparar jobs só pros packages afetados.
| Tool | Modelo | Hermético | Cache local | Cache remoto | Quando |
|---|---|---|---|---|---|
| Turborepo | Hash de inputs (files + deps + env) | Não (best-effort) | .turbo/ local | Vercel Remote Cache, AWS S3, Cloudflare R2, self-host (open spec) | Default 2026 pra Next/JS/TS monorepos |
| Nx | Mesmo modelo + plugins por linguagem (Angular, React Native, Go, Rust) | Não | node_modules/.cache/nx | Nx Cloud (paga), self-host com nx-cloud-server | Times Angular/Nx-shop ou poliglota com plugins |
| Bazel | Sandbox + reprodutibilidade rigorosa | Sim | disk cache + action cache | BuildBuddy, EngFlow, Buildbarn, Bazel Remote Cache (open) | Polyglot massivo (Google/Lyft/Stripe scale) ou criticidade hermetic |
| Pants | Bazel-like, foco Python/JVM | Sim | local + remote | Toolchain remoto | Python-heavy monorepos (Twitter, Toolchain customers) |
| Rush.js (Microsoft) | npm/pnpm workspaces oriented | Não | local | Phased builds em Azure Pipelines | TS-only monorepos enterprise |
Hermético (sandboxed): build em diretório isolado; só vê inputs declarados. Reprodutível bit-exato. Custa setup pesado e curva de aprendizado; ganho cresce com tamanho do repo.
1. Path-based (mais simples, menos preciso)
# .github/workflows/ci.yml
jobs:
detect:
runs-on: ubuntu-latest
outputs:
site: ${{ steps.f.outputs.site }}
api: ${{ steps.f.outputs.api }}
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- id: f
uses: dorny/paths-filter@v3
with:
filters: |
site:
- 'apps/site/**'
- 'packages/ui/**' # dependência de site
api:
- 'apps/api/**'
- 'packages/db/**'
build-site:
needs: detect
if: needs.detect.outputs.site == 'true'
runs-on: ubuntu-latest
steps: [...]
Limite: você mantém manualmente o mapa "package depende de package". Erra quando refactor cross-package.
2. Affected via tool (Turbo/Nx) — preciso, automático
# Em PR contra main, calcula affected automaticamente do git diff
turbo run build --filter='[origin/main]'
turbo run test --filter='...{[origin/main]}' # affected + downstream
# Nx equivalente
nx affected --target=build --base=origin/main
nx affected --target=test --base=origin/main
...{[origin/main]} (Turbo) ou affected --withRelated (Nx) inclui packages que dependem dos modificados — cobertura segura sem rodar tudo.
3. Bazel target-based — máxima precisão
# Lista alvos afetados pelo diff (bazel-diff tool)
bazel-diff get-impacted-targets-by-diff \
--workspacePath . \
--bazelPath $(which bazel) \
--startingRevision $(git merge-base HEAD origin/main) \
--finalRevision HEAD \
--output impacted.txt
bazel test $(cat impacted.txt | xargs)
Custa setup bazel-diff + analysis caching; vence em monorepo de 100k+ targets.
Sem cache remoto, novo dev clona repo e roda pnpm build — 8min cold. Com cache remoto que outro dev populou, mesmo build pega artifacts já-buildados — 30s.
Turborepo Remote Cache (open spec):
# Self-hosted via Cloudflare Workers (gratis pra most teams)
# https://github.com/AdiRishi/turborepo-remote-cache-worker
echo "TURBO_API=https://your-worker.your-domain.workers.dev" >> .env
echo "TURBO_TEAM=mycompany" >> .env
echo "TURBO_TOKEN=$(openssl rand -hex 32)" >> .env
# Em CI:
turbo run build --remote-cache-timeout=10
Nx Cloud (paga; gratis tier limitado): ~$25-99/dev/mês; integra com Nx Console pra dashboards de cache hit rate.
Bazel BuildBuddy / EngFlow: SaaS ou self-host; remote build execution (RBE) também — workers em cluster K8s próprio, build paralelizado em N machines.
logistics-monorepo/
├── apps/
│ ├── site/ # Next.js público
│ ├── courier-app/ # Expo
│ └── api/ # Fastify backend
├── packages/
│ ├── ui/ # Design system shared
│ ├── db/ # Drizzle schema + queries
│ ├── auth/ # auth client/server
│ └── tsconfig/ # tsconfig shared
├── turbo.json
└── pnpm-workspace.yaml
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env", "tsconfig.base.json"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"],
"cache": true
},
"test": {
"dependsOn": ["^build"],
"outputs": ["coverage/**"]
},
"lint": { "cache": true, "outputs": [] },
"typecheck": { "dependsOn": ["^build"], "outputs": [] },
"dev": { "cache": false, "persistent": true }
}
}
CI workflow:
- run: pnpm install --frozen-lockfile
- run: turbo run lint typecheck test build --filter='...{[origin/main]}'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: 'logistics'
Resultado em PR pequeno (packages/ui button styling): apenas ui + site + courier-app rebuildam; api cache hit. CI baixa de 12min pra 90s.
turbo run --output-logs=full | grep "cache hit". Abaixo de 70% em PR típico = cache config errada (input não declarado, env var vazando como input).process.env.X em build. Solução: declarar globalEnv: ["X"] em turbo.json ou injetar via --env-mode=strict.dockerized builds em CI.Cruza com 03-04 §2.4 (caching strategies em CI são fundamento), 02-04 (Next.js build é o consumidor mais frequente), 04-12 §2.10 (roadmap técnico inclui investment em build infra).
Pipeline performance:
CI lento é dívida de produtividade. < 15 min ideal pra PR; < 5 min pro essencial.
Metrics canônicas (Forsgren, Humble, Kim — Accelerate, 2018) viraram industry standard. Mas a maioria mede errado ou não mede. Como mensurar em GitHub Actions + Railway (stack típico):
| Métrica | Definição | Fonte | Query/cálculo |
|---|---|---|---|
| Deployment Frequency | Quantos deploys de prod / período | GH workflow_runs status=success no job deploy | count(deploys) / días |
| Lead Time for Changes | Tempo do commit ao deploy | Diff entre commit.author.date e deploy.completed_at | median(deploy_time - first_commit_time) por PR |
| Change Failure Rate | % de deploys que dispararam incidente/rollback | Tag de incidentes correlacionando com deploy hash | count(failed_deploys) / count(total_deploys) |
| Mean Time to Restore (MTTR) | Tempo do incidente abrir até resolver | Incident management tool (PagerDuty, Linear, OpsGenie) | median(resolved_at - opened_at) |
Implementação prática (GitHub Actions + Railway):
# .github/workflows/deploy.yml — adiciona timestamps em outputs
- name: Record deploy
run: |
gh api -X POST /repos/${{github.repository}}/dispatches \
-f event_type=dora-deploy \
-f client_payload='{"sha":"${{github.sha}}","timestamp":"${{ steps.deploy.outputs.completed_at }}"}'
Persistir em DB próprio (Postgres) ou stack de obs (Grafana com loki tags). Query SQL pra weekly report:
SELECT date_trunc('week', deploy_at) AS week,
COUNT(*) AS deploys,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM (deploy_at - first_commit_at))) AS lead_time_p50_sec
FROM deploys WHERE branch='main' AND created_at > now() - interval '90 days'
GROUP BY 1 ORDER BY 1 DESC;
Categorias por performance (DORA 2024 State of DevOps Report):
| Tier | Deploy freq | Lead time | MTTR | CFR |
|---|---|---|---|---|
| Elite | Multiple/day | < 1 hour | < 1 hour | 0-15% |
| High | Weekly-monthly | 1 day - 1 week | < 1 day | 16-30% |
| Medium | Monthly-bi-yearly | 1 week - 1 month | 1 day - 1 week | 16-30% |
| Low | < bi-yearly | > 6 months | > 1 week | 16-30% |
Tools ready-made (zero implementação):
Anti-padrões a evitar:
Cruza com 03-15 (incident management gera input pra MTTR), 04-12 (tech leadership usa DORA pra calibration de time).
GitHub free runners (ubuntu-latest) limitados em concorrência e specs. Self-hosted:
actions-runner-controller.Self-hosted resolve cost em volume alto e specs específicas (GPUs, builds Mac iOS). Adiciona ops.
iOS:
Android:
EAS Build (Expo) terceriza tudo.
Strategy decision matrix:
| Strategy | Cost | Rollback time | Use when |
|---|---|---|---|
| Recreate | Lowest infra | minutes | Dev/staging, downtime ok |
| Rolling | Low | seconds | Most stateless services |
| Blue/Green | 2x infra | seconds | Zero-downtime mandatory, batch DB migrations |
| Canary | +20% infra | seconds | High-risk change, observable metrics |
| Progressive (com metrics gate) | +20% infra | automatic | SaaS com diverse customer impact |
| Shadow | 2x infra | n/a (no traffic) | Validar perf sem user impact |
kubectl set image deployment/api api=registry/api:v2 --record substitui pods gradualmente. Defaults: maxSurge: 25% + maxUnavailable: 25%. Em prod, force maxUnavailable: 0 (pod novo nasce ready antes de antigo morrer).
Pegadinha: readinessProbe mal calibrada → traffic vai pra pod sem app pronta. Implemente readiness lendo state real (DB connection, cache warmup, dependency health), não só GET / que responde 200 antes do app boot.
Rollback: kubectl rollout undo deployment/api (history default 10 revisions; tune via revisionHistoryLimit).
Dois ambientes completos (Blue current, Green new). LB faz switch instantâneo de todo traffic.
Pattern K8s: Deployments api-blue + api-green; Service selector version: blue → switch:
kubectl patch service api -p '{"spec":{"selector":{"version":"green"}}}'
Schema migration: backward-compat MANDATÓRIO. Add column nullable; dual-write durante cutover; drop em release N+2 (ver expand-migrate-contract abaixo). Custo: 2x infra durante cutover (minutos a horas). Trade-off aceitável pra zero-downtime + instant rollback.
Deploy pra subset (5-10%) traffic. Monitora métricas. Aumenta gradualmente se healthy.
Argo Rollouts 1.7+ (controller K8s, OSS): canary declarativo:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata: { name: api-orders }
spec:
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 5m }
- analysis:
templates: [{ templateName: success-rate }]
- setWeight: 25
- pause: { duration: 10m }
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
Alternativas: Flagger 1.36+ (Flux ecosystem). Service mesh integration: Istio VirtualService weights, Linkerd TrafficSplit. AnalysisTemplate consulta Prometheus (success rate, p99 latency, error budget burn).
Pegadinha: canary com 5% traffic em service low-traffic precisa rodar 30+min pra signal estatístico; em janela noturna o noise dominates.
Canary com auto-promote OU auto-rollback baseado em SLI metrics.
Promotion criteria típico: error rate < 0.5%, p99 latency increase < 20% vs baseline, Apdex > 0.95 sustentado 10min. Auto-rollback triggers: error rate spike, p99 > 2x baseline, alert externo (PagerDuty webhook).
Tooling 2026: Argo Rollouts + Prometheus + AnalysisTemplate; Flagger + Linkerd; Spinnaker (legacy enterprise, evite em greenfield).
Deploy v2 recebe traffic via mirror (tee), mas responses descartadas. Útil pra perf testing sob real load sem user impact. Istio: mirror: em VirtualService.
Use case: novo query plan Postgres; mirror real workload, compare latencies, zero risk. Nunca shadow em service com side effects (emails, payments) sem dry-run mode — duplicate effects em prod.
Decoupling deploy de release: deploy code com flag OFF; turn ON gradualmente per cohort.
Tooling 2026:
Pattern: server-side evaluation pra flags afetando business logic; client-side só pra UI cosmetic. Cache eval ~30s pra evitar network call per request em hot path.
Expand-Migrate-Contract:
-- Release N (expand)
ALTER TABLE orders ADD COLUMN customer_uuid UUID; -- nullable
-- Release N+1 (migrate): backfill async + dual-write em app
UPDATE orders SET customer_uuid = lookup(customer_id) WHERE customer_uuid IS NULL;
-- Release N+2 (contract)
ALTER TABLE orders DROP COLUMN customer_id;
Online schema migration: gh-ost (GitHub MySQL), pt-online-schema-change (Percona), pg_repack (Postgres). Postgres 11+ otimizou ADD COLUMN ... NOT NULL DEFAULT 'X' (pre-11 fazia rewrite full table). PG 12+ ALTER TABLE non-locking adds frequentemente mais rápido que tooling externo.
Stack: K8s + Argo Rollouts + Argo CD + Prometheus + Statsig.
Strategy escolhida pra api-orders: Progressive delivery com analysis gate.
new_routing_engine per cohort (1% → 10% → 50% → 100%).pg_repack pra rewrites.kubectl rollout undo sem validar revisionHistoryLimit (history truncado; old undo impossible).latest tag em image (digest hash mandatório pra reproducibility e rollback determinístico).Cruza com 03-03 (K8s, Deployment + Service patterns), 03-15 (incident response, deploy correlated to incidents), 03-07 (observability, metrics drive analysis), 04-09 (scaling, blast radius por strategy), 02-10 (ORMs, schema migration patterns).
Humanos são péssimos em escrever release notes. Esquecem mudanças, omitem breaking changes, copiam template do release anterior. A solução é gerar tudo a partir dos commits: conventional commits viram changelog, changelog vira version bump, version bump vira tag + GitHub Release. Sem intervenção manual entre git push e o release publicado. Stack 2026 dominante: release-please-action v4 (Google, monorepo + single-repo), @changesets/cli v2.27+ (Atlassian/Vercel, monorepo independent versioning), semantic-release v24+ (alternativa zero-config single-package).
Conventional Commits v1.0.0 spec. Formato fixo: <type>(<scope>)?: <description>. Types canônicos: feat (MINOR bump), fix (PATCH bump), docs, style, refactor, perf, test, build, ci, chore. Breaking change marca com ! após type/scope OU footer BREAKING CHANGE:. Exemplos:
feat(auth): add OAuth2 PKCE flow
fix(api): handle null token on refresh endpoint
feat(api)!: rename /users endpoint to /accounts
BREAKING CHANGE: clients devem migrar pra /accounts; /users responde 410 por 30 dias
Enforce com commitlint (@commitlint/config-conventional) + husky pre-commit hook. PRs com squash-merge: o título do PR vira o commit; configure GitHub branch protection pra exigir título conventional via action amannn/action-semantic-pull-request@v5.
Semver decision tree. Dado mudança X, qual bump?
public API quebrou (signature change, removed export, throw em path antes safe)?
-> MAJOR (1.2.3 -> 2.0.0)
adicionou feature backward-compatible (novo export, novo param opcional, novo endpoint)?
-> MINOR (1.2.3 -> 1.3.0)
bug fix sem mudar API (lógica interna, perf, docs)?
-> PATCH (1.2.3 -> 1.2.4)
ainda em 0.x (unstable)?
-> regras frouxas: MINOR pode quebrar; > 1.0.0 quando API estabilizar
Internal lib em monorepo: tratar consumers internos como public API. Bump major exige migration guide + janela de coexistência.
Tools comparison — quando cada.
| Tool | Sweet spot | Pain |
|---|---|---|
| release-please-action v4 | Polyglot single-repo OU monorepo lockstep; Go/Java/Node/Python; usa só commits | Independent versioning em monorepo é verboso; precisa release-please-config.json |
| @changesets/cli v2.27 | Monorepo Node (pnpm/yarn workspaces) com independent versioning; explicit changeset per PR | Requer disciplina: dev escreve .changeset/*.md no PR (não 100% auto) |
| semantic-release v24 | Single-package npm, fully zero-touch; plugin ecosystem (slack, jira) | Monorepo é 2nd-class; opinionated e difícil custom |
Regra: monorepo Node com pacotes published independently -> changesets. Monorepo polyglot OU repo único -> release-please. Lib npm single-package -> semantic-release.
release-please workflow real (GitHub Actions). Cria "Release PR" agregando commits desde último release; merge -> tag + GitHub Release + CHANGELOG.md commit:
# .github/workflows/release-please.yml
name: release-please
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
token: ${{ secrets.GITHUB_TOKEN }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
- uses: actions/checkout@v4
if: ${{ steps.release.outputs.release_created }}
- uses: actions/setup-node@v4
if: ${{ steps.release.outputs.release_created }}
with: { node-version: '22', registry-url: 'https://registry.npmjs.org' }
- run: npm ci && npm publish --provenance --access public
if: ${{ steps.release.outputs.release_created }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
release-please-config.json (monorepo lockstep):
{
"release-type": "node",
"include-component-in-tag": false,
"packages": {
"packages/core": { "package-name": "@acme/core" },
"packages/cli": { "package-name": "@acme/cli" }
},
"plugins": [{ "type": "node-workspace" }]
}
Changesets workflow (monorepo independent versioning). Dev roda pnpm changeset no PR, escolhe pacotes afetados + bump (patch/minor/major) + descrição. Arquivo .changeset/witty-foxes-dance.md:
---
"@acme/api": minor
"@acme/sdk": patch
---
Add cursor pagination to /events; SDK now retries 429 com exponential backoff.
Action consume changesets no merge:
# .github/workflows/changesets.yml
name: changesets
on: { push: { branches: [main] } }
jobs:
release:
runs-on: ubuntu-latest
permissions: { contents: write, pull-requests: write, id-token: write }
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with: { node-version: '22', registry-url: 'https://registry.npmjs.org' }
- run: pnpm install --frozen-lockfile
- uses: changesets/action@v1
with:
publish: pnpm release # script que roda changeset publish
version: pnpm version-packages
commit: "chore: version packages"
title: "chore: version packages"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Action abre "Version Packages" PR; merge dispara pnpm release -> bump + publish + tag por pacote.
CHANGELOG.md generation. Nunca escreva à mão. release-please regenera por commit type (Features / Bug Fixes / Performance / BREAKING CHANGES). Changesets usa @changesets/changelog-github pra linkar PR + autor:
// .changeset/config.json
{
"$schema": "https://unpkg.com/@changesets/config@3/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "acme/monorepo" }],
"commit": false,
"fixed": [],
"linked": [["@acme/api", "@acme/api-types"]],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["@acme/example-app"]
}
linked: pacotes que bumpam juntos (mas independente do resto). fixed: pacotes sempre na mesma versão (lockstep subset).
Prerelease channels (alpha/beta/rc). Pre-1.0 ou breaking releases publicam em dist-tag separada; consumers opt-in:
# changesets prerelease mode
pnpm changeset pre enter beta
pnpm changeset # cada PR vira 2.0.0-beta.0, beta.1, ...
pnpm changeset version
pnpm changeset publish # publica com --tag beta
pnpm changeset pre exit # finaliza -> 2.0.0
# consumer
npm install @acme/api@beta # pega 2.0.0-beta.5
npm install @acme/api # ainda 1.x.x estável
release-please usa release-as no commit footer pra forçar prerelease:
feat: new auth flow
Release-As: 2.0.0-rc.1
Stack Logística aplicada. API freight-api (single-repo Go + Node SDK), release-please em lockstep. Cada PR squash-merged com título feat(routing): add multi-stop optimization -> release-please abre PR chore(main): release 1.7.0 agregando 14 commits desde 1.6.3. CHANGELOG.md auto-gerado: 6 features, 4 fixes, 1 breaking (com migration note). Merge -> tag v1.7.0, GitHub Release com notes, Docker image freight-api:1.7.0 + :1.7 + :1 build no workflow downstream (trigger por release.created). Customer SDK (@logistica/freight-sdk) em changesets independent: bump minor sozinho quando endpoint novo é adicionado, sem forçar major no app principal.
Anti-patterns.
npm why + grep antes).gh release create direto, bypass do PR (sem audit trail; release-please PR é o registro).rc ou beta em prod por engano (dist-tag confusion; CI valida version.includes('-') -> bloqueia deploy prod).feat: (consumer toma 500; ! ou footer BREAKING CHANGE: mandatório).0.x.y por 3 anos com clientes pagantes (semver não aplica abaixo de 1.0; estabilize antes de cobrar SLA).linked).npm publish sem --provenance (2026 supply chain mínimo; sigstore + GitHub OIDC mandatório).Cruza com 03-04 §2.10 (versioning + changelog basics), 03-04 §2.13 (artifacts, image tagging), 03-04 §2.18 (mobile pipeline, store versioning), 01-09 (git internals, tag objects + signed tags), 03-15 (incident response — release tags são bisect anchor), 04-08 (microservices contract versioning, gRPC/OpenAPI compat), 03-09 §2.21 (CI/CD pipeline com image build optimization step), 03-17 §2.22 (a11y como deploy gate via axe-playwright + Lighthouse CI), 04-15 §2.20 (npm provenance + Sigstore + GitHub Actions OIDC publish em release flow).
Você precisa, sem consultar:
Construir o pipeline CI/CD do Logística v1, com promoção até produção em K8s.
git-sha + main-latest.latest em deploy prod.Threshold de Maestria
Acerte todas as 5 pra marcar o módulo como concluído. Sem pressa, sem timer. Tudo fica salvo no teu navegador.
Q1Qual a diferença essencial entre Continuous Delivery e Continuous Deployment?
Q2Por que usar OIDC entre GitHub Actions e AWS é superior a guardar AWS access keys nos GH Secrets?
Q3Em deploy strategy, qual a vantagem do canary com `setWeight` progressivo + analysis gate vs blue/green?
Q4Qual é a métrica DORA `Lead Time for Changes` quando medida CORRETAMENTE?
Q5Por que Trunk-based + feature flags é dominante em 2026 vs GitFlow para SaaS?
Destrava
03-04 é prereq dos seguintes módulos: