Compose, Makefile, .infra e workflows de CI

TLDR: Makefile delegador, compose.yml unificado, .infra/ por módulo e por projeto, e workflows de CI com detected changes — o padrão wehive adaptado para multi-módulo.

Estado atual: PR 2 (Makefile + compose + .module/) e PR 4 (workflows) estão entregues — .github/workflows/ tem review-pr.yml, check-main.yml, deploy-staging.yml e deploy-production.yml. Do PR 3, os dois módulos têm .infra/ (build-args, k8s, terraform); falta apenas o .infra/ compartilhado na raiz (VPC, RDS, Redis). Por isso o status segue in_progress.

Contexto

O projeto tem a estrutura modules/ estabelecida mas sem Makefile, compose.yml, .infra ou CI. Precisa de tudo isso seguindo os padrões wehive, adaptados para multi-módulo.

Referências: marketing/ (Makefile delegador), messenger-api (workflows, nomes), trgclub (padrão review-pr + main).

Objetivos

  • Makefile na raiz delega para cada módulo: make frontend.<target>, make backend.<target>.
  • compose.yml na raiz inclui o stack do commons + overrides por módulo via .module/docker/.
  • .infra/ na raiz para infra compartilhada (RDS, VPC, Redis); .infra/ em cada módulo para k8s + terraform do módulo.
  • Workflows de CI com detected changes — um arquivo por responsabilidade, duas trilhas no deploy.

Fora de escopo

  • Conteúdo de deploy do back-end — o módulo do back ainda não tem app quando esta spec começa.
  • Qualquer mudança no código dos módulos.

Mudanças

Layout resultado

nectar-charges/ ├── Makefile # delega: frontend.%, backend.% ✓ PR2 ├── compose.yml # inclui stack react + .module/docker/ ✓ PR2 ├── .env.example # ✓ PR2 ├── .infra/ # infra compartilhada (RDS, VPC, Redis) ✗ pendente │ ├── terraform/ │ └── k8s/ ├── modules/ │ ├── frontend/ │ │ ├── .module/ # ✓ PR2 │ │ │ ├── make/main.mk │ │ │ └── docker/compose.yml │ │ ├── .infra/ # ✓ PR3 │ │ │ ├── k8s/ │ │ │ │ ├── base/ # deployments: web, worker │ │ │ │ └── overlays/staging/ + production/ │ │ │ └── terraform/ # secrets, DNS do frontend │ │ ├── Makefile # ✓ PR2 │ │ └── src/ ... │ └── backend/ │ ├── .module/ # ✓ PR2 │ ├── .infra/ # ✓ PR3 │ └── Makefile # ✓ PR2 └── .github/ └── workflows/ # ✓ PR4 ├── review-pr.yml # PR: checks + infra plan com detected changes ├── check-main.yml # push main: checks + infra apply com detected changes ├── deploy-staging.yml # push tag v*: duas trilhas frontend + backend └── deploy-production.yml # workflow_dispatch: delivery manual

Decisão: infra de projeto vs. infra de módulo

Onde O que fica
.infra/ raiz Recursos compartilhados: VPC, RDS, Redis, namespace k8s base
modules/frontend/.infra/ Manifests k8s do frontend, secrets específicos, DNS do frontend
modules/backend/.infra/ Manifests k8s do backend, secrets específicos, DNS do backend

O terraform do módulo referencia outputs do terraform do projeto.

Decisão: namespace k8s e nomenclatura de pods

Namespace único por ambiente — frontend e backend escalam independentemente via Deployment + HPA, não via namespace separado:

namespace: nectar-charges--staging deployment: frontend-web ← HPA independente deployment: frontend-worker ← HPA independente (se existir) deployment: backend-web ← HPA independente deployment: backend-worker ← HPA independente (se existir)

app_name por módulo: nectar-charges-frontend, nectar-charges-backend — usado como nome da imagem no ECR e prefixo dos manifests k8s.

Decisão: nomes e organização dos workflows

Padrão trgclub. Infra não tem arquivo separado — o plan entra no review-pr.yml, o apply entra no workflow de main.

Arquivo Nome do workflow Trigger
review-pr.yml review -> pr pull_request
check-main.yml check -> main push em main
deploy-staging.yml deploy -> staging push de tag v*
deploy-production.yml deploy -> production [manual] workflow_dispatch

Detected changes (review-pr e main)

```yaml jobs: changes: outputs: frontend: ${{ steps.filter.outputs.frontend }} backend: ${{ steps.filter.outputs.backend }} frontend-infra: ${{ steps.filter.outputs.frontend_infra }} backend-infra: ${{ steps.filter.outputs.backend_infra }} project-infra: ${{ steps.filter.outputs.project_infra }} steps: - uses: dorny/paths-filter@v3 with: filters: | frontend: [‘modules/frontend/’, ‘!modules/frontend/.infra/’] backend: [‘modules/backend/’, ‘!modules/backend/.infra/’] frontend_infra: [‘modules/frontend/.infra/’] backend_infra: [‘modules/backend/.infra/’] project_infra: [‘.infra/**’]

check-frontend: needs: changes if: needs.changes.outputs.frontend == ‘true’ uses: ibft-corp/pipelines/.github/workflows/check-react.yml@v1

check-backend: needs: changes if: needs.changes.outputs.backend == ‘true’ uses: ibft-corp/pipelines/.github/workflows/check.yml@v1

infra-frontend: # plan no review-pr, apply no main needs: changes if: needs.changes.outputs.frontend-infra == ‘true’

infra-backend: needs: changes if: needs.changes.outputs.backend-infra == ‘true’

infra: # infra compartilhada do projeto needs: changes if: needs.changes.outputs.project-infra == ‘true’ ```

deploy-staging — duas trilhas, uma tag

A tag v* dispara o workflow. Detected changes (diff entre a tag atual e a anterior) decide quais trilhas rodam. Cada trilha é independente:

```yaml check-frontend: uses: ibft-corp/pipelines/.github/workflows/check-react.yml@v1

infra-frontend: needs: changes if: needs.changes.outputs.frontend_infra == ‘true’ uses: ibft-corp/pipelines/.github/workflows/infra.yml@v3 with: app_name: nectar-charges-frontend working_directory: modules/frontend

package-frontend: needs: [check-frontend, infra-frontend] if: | always() && needs.check-frontend.result == ‘success’ && needs.infra-frontend.result != ‘failure’ uses: ibft-corp/pipelines/.github/workflows/package.yml@v1 with: app_name: nectar-charges-frontend

delivery-frontend: needs: package-frontend uses: ibft-corp/pipelines/.github/workflows/delivery.yml@v1 with: app_name: nectar-charges-frontend environment: staging

trilha backend — mesma estrutura

```

O if: always() em package-* torna explícito no log quando infra-* foi skipped. O guard != 'failure' bloqueia o deploy se o apply quebrar.

Sequência de entrega

PR Entrega Estado
PR 2 Makefile + compose + .module/ ✓ concluído
PR 3 .infra/terraform/ da raiz; modules/frontend/.infra/ e modules/backend/.infra/ (k8s base + overlays staging/production, terraform de secrets e DNS) parcial — os dois módulos prontos, falta o da raiz
PR 4 Os 4 workflows + atualizar as skills commons:ci e commons:structure ✓ concluído

Como verificar

PR 3:

  • ls modules/frontend/.infra/k8s/overlays/staging/ — manifests presentes
  • ls .infra/terraform/ — scaffold presente

PR 4:

  • PR alterando só modules/frontend/src/ → apenas check-frontend roda
  • PR alterando só modules/frontend/.infra/ → apenas infra-frontend roda
  • PR alterando ambos → ambos rodam
  • Push da tag v1.0.0 com mudança só no frontend → trilha frontend roda, backend skipped
  • Push em main com mudança em .infra/terraform/ → infra (projeto) roda

Documentação

  • Convenção de módulos — seção .infra/ por módulo vs. projeto
  • Skill commons:structure — layout completo
  • Skill commons:infra — .infra dentro de módulo vs. na raiz
  • Skill commons:ci — padrão de detected changes multi-módulo