Reorganização da infraestrutura em stateful e stateless

TLDR: Quebrar o state monolítico do projeto MKT em states isolados por serviço, separando recursos com dado (stateful/) dos recursos de computação (stateless/), para que um terraform destroy nunca alcance o banco.

Contexto

A infraestrutura do MKT tinha banco, cache e aplicações no mesmo state do Terraform. Isso criava quatro problemas:

  1. Risco de perda de dado — terraform destroy no MKT levava os dados do banco junto.
  2. Proteção insuficiente — prevent_destroy é contornável com a flag -target.
  3. Scripts complexos — todo script calculava caminhos relativos como ../../../../../bin/tf.
  4. Sem separação — recursos com dado e recursos de computação misturados.

Objetivos

  • State isolado por serviço, para que falhas e destroys não cascateiem.
  • prevent_destroy em banco e cache, que passam a ser destruídos explicitamente e em separado.
  • Configuração do messagebroker (vhost/user) separada do runtime da aplicação, para recriar uma sem tocar na outra.
  • Um helper de bootstrap que elimine o cálculo de caminho relativo nos scripts.
  • Hierarquia de targets make em quatro níveis para apply, plan, taint e destroy.

Fora de escopo

  • Migração de dado. A decisão foi destruir o MKT existente e reconstruir do zero — o projeto estava em fase de teste, o dado podia ser recriado e a mesa limpa evitava drift de state escondido.
  • Granularidade dentro de shared/ (kubernetes, messagebroker) — ficou para depois.
  • Gerador de template para novos contextos.

Mudanças

Layout

``` bootstrap/ ├── env.sh # helper: carrega .env e exporta a função tf() └── install.sh # instala o wehive em /usr/local/bin

src/stacks/ ├── shared/terraform/ # INALTERADO (kubernetes + messagebroker) ├── stateful/mkt/ │ ├── database/terraform/ # state isolado + prevent_destroy │ └── cache/terraform/ # state isolado + prevent_destroy └── stateless/mkt/n8n/ ├── prepare/terraform/ # vhost/user do messagebroker └── runtime/terraform/ # deploy no App Platform ou Kubernetes ```

Hierarquia de targets

```makefile # Nível 1: terraform específico (grão mais fino) stateful.mkt.database.apply stateful.mkt.cache.apply stateless.mkt.n8n.prepare.apply stateless.mkt.n8n.runtime.apply

Nível 2: aplicação completa (prepare + runtime)

stateless.mkt.n8n.apply

Nível 3: camada stateful / stateless

stateful.mkt.apply stateless.mkt.apply

Nível 4: projeto completo

mkt.apply ```

Helper de bootstrap

bootstrap/env.sh detecta a raiz do projeto (via git rev-parse --show-toplevel ou presença de .env), carrega o .env e exporta uma função tf() que chama $PROJECT_ROOT/bin/tf. Todo script passa a começar com source wehive (ou o fallback para bootstrap/env.sh) em vez de calcular caminho relativo.

Estrutura do state

wehive-terraform-states/ └── stacks/ ├── shared/terraform.tfstate ├── stateful/mkt/{database,cache}/terraform.tfstate └── stateless/mkt/n8n/{prepare,runtime}/terraform.tfstate

Riscos aceitos

Risco Mitigação
Perda de dado na reorganização MKT em teste; dado recriável
Scripts quebram na transição testar o helper de bootstrap primeiro
Conflito de state usar chaves de state completamente novas
Complexidade dos makefiles hierarquia de 4 níveis com nomenclatura consistente

Como verificar

  • Toda a infraestrutura do MKT sobe com a estrutura nova.
  • Os 4 níveis de atalho make funcionam.
  • O comando wehive está instalado e funcional.
  • Nenhum caminho relativo restou nos scripts.
  • Destruir o stateless não afeta o stateful.
  • Banco e cache têm prevent_destroy.

Documentação

Nota histórica: a separação stateful/stateless sobreviveu, mas os caminhos definidos aqui foram alterados depois pela reestruturação da infraestrutura, que moveu makefiles/ para .project/make/ e src/stacks/shared/ para src/shared/.