Arquitetura & Stacks
Regras que valem em qualquer projeto, salvo override explícito.
adapters → ports → domain, nunca o inverso.pgx/v5 + interface DBTX.chi v5. Nunca gin, echo, gorilla.net/http. Sem libs externas.log/slog, JSON estruturado.scripts/*.sh + task. Nada ad-hoc.build e deploy dependem de test. Cobertura ≥ 90%.pnpm. Nunca npm/yarn.pass. Tolerância zero a plaintext.timeout 30s em todo comando + log com tee /tmp/log.txt.Go Backend — Hexagonal
Ports & Adapters. Domínio puro, mundo externo só atrás de interface, wiring em cmd/.
# layout canônico backend/ ├── cmd/server/main.go # entrypoint chi — todo o DI aqui │ ├── worker/main.go # Temporal worker │ └── migrate/main.go ├── domain/ │ ├── entity/ # entidades puras — ZERO deps externas │ └── service/ # lógica de negócio ├── ports/ │ ├── inbound/ # SessionManager, WebhookValidator... │ └── outbound/ # XxxRepository, Transcriber, DBTX... ├── adapters/ │ ├── driven/ # 1 pasta por serviço externo │ │ ├── postgres/ temporal/ stripe/ groq/ openrouter/ email/ ... │ └── driving/http/ # rotas chi + handlers + middleware ├── internal/config/ # env vars validadas no boot (fail fast) │ └── observability/ # Sentry + slog middleware └── go.mod # go 1.26
📦Libs padrão
go-chi/chi/v5jackc/pgx/v5pashagolub/pgxmock/v4stretchr/testifygo.temporal.io/sdklog/slog·net/http
🧪Testes
- Domain: 100%, table-driven,
testdata/ - Adapters: >90% — pgxmock, httptest, testsuite
go test ./... -cover -race- Gate <90% bloqueia CI
- Zero flaky tolerado
🏷️Naming
- Adapter = nome do serviço (
stripe/,groq/) - Repos:
XxxRepository - Capacidades:
Transcriber,Messenger - DI só em
cmd/*/main.go - Guard de env perigosa no config
Frontend — Next.js 16
App Router, React 19, Tailwind 4, pnpm, vitest. Middleware agora é proxy.ts.
frontend/src/ ├── app/ │ ├── (auth)/ # login, register, update-password │ ├── (dashboard)/ # protegido — layout force-dynamic │ ├── api/ # route handlers (callback, webhook) │ ├── providers.tsx · globals.css · layout.tsx │ └── proxy.ts # middleware (rename do Next 16) ├── components/<feature>/ + ui/ # Radix + custom ├── hooks/ useAuth.ts ... ├── lib/ │ ├── api.ts # apiFetch() — NUNCA fetch() cru │ └── supabase/ client·server·middleware └── types/ · test/
⚡Convenções críticas
apiFetch(): JWT + 401/403 → signOut + redirect- Rotas internas versionadas
/v1 - Página por-usuário:
force-dynamic - OAuth callback: criar
responseANTES do client Supabase - Logout:
router.refresh()antes depush() - SSE: token via
?token=(sem headers)
🛠️Build & testes
NEXT_PUBLIC_*= build-time → build args no fly.toml- Atrás de proxy: tratar
x-forwarded-host pnpm vitest run· por path ·-t "nome"- eslint 9 + eslint-config-next
- Tailwind 4 via
@tailwindcss/postcss
DevOps
Toda automação roda via Task (go-task) — cada projeto tem um Taskfile.yaml v3 e nada executa fora dele: nunca comando ad-hoc no shell. A lógica vive em scripts/*.sh (bash, set -euo pipefail), a task só embrulha o script e loga com tee. Task names são a API pública do projeto (task -l = documentação); scripts/ é a trilha de auditoria.
# vocabulário Taskfile — task names são contrato dev dev:api dev:worker web:dev test test:backend test:frontend test:coverage # dependência de build/deploy lint build # CGO_ENABLED=0, deps:[test] supabase:start supabase:reset migrate migrate:local deploy deploy:backend deploy:frontend deploy:worker logs:fly status:fly health plan apply dev:apply prd:apply # repos IaC — prd sempre com prompt: vpn:up vpn:down vpn:status # acesso a recursos privados
# anatomia Taskfile v3 — gates, args, idempotência build: deps: [test] # teste falhou = não builda cmds: [./scripts/build.sh 2>&1 | tee /tmp/build.log] apply: desc: 'Uso: task apply -- env/dev/vpc' cmds: [terragrunt apply --working-dir {{.CLI_ARGS}}] prd:apply: prompt: "PRODUCAO: confirma apply em prd?" # destrutivo/prod = prompt obrigatório supabase:start: status: [supabase status > /dev/null 2>&1] # skip se já rodando
# Docker multi-stage → chainguard (0 CVEs) FROM golang:1.26-alpine AS builder RUN CGO_ENABLED=0 go build -ldflags "-X main.Version=${VERSION}" -o server ./cmd/server FROM chainguard/static:latest COPY --from=builder /app/server /server ENTRYPOINT ["/server"]
# IaC — Terragrunt Stacks (OpenTofu) — wrapper YAML é O padrão: # cada componente é configurado por manifest YAML estilo CRD; HCL fica genérico infra/ ├── root.hcl # locals: project, modules_base + remote_state ├── _units/<comp>/terragrunt.hcl # templates parametrizados (vpc, rds, alb, ecs...) ├── env/{dev,qas,prd}/ # env.hcl: environment, region, account_id, module_ref └── manifests/{env}/<comp>.yaml # wrapper YAML: apiVersion/kind/metadata/spec → yamldecode # unit: backend + provider GERADOS, módulo por git tag generate "backend" { contents = s3 key "{env}/{comp}/terraform.tfstate" + dynamodb lock } generate "provider" { contents = default_tags Project/Environment/ManagedBy } terraform { source = "${modules_base}/<module>?ref=${local.ref}" } # repo separado, semver inputs = merge(yamldecode(file("manifests/${env}/<comp>.yaml")).spec, {...})
# Ansible — playbook em fases, inventário YAML, orquestração do CP[0] - name: "Fase 1 — Preparar OS" # role prepare: sysctl 30+, modprobe, UFW, swap off hosts: microk8s become: yes roles: [prepare] - name: "Fase 3 — Join nodes" hosts: control_plane[0] # orquestra do primeiro CP tasks: - command: microk8s kubectl cluster-info register: api until: api.rc == 0 retries: 18 delay: 10 - include_tasks: tasks/join-node.yaml loop: "{{ groups['control_plane'][1:] + groups['workers'] }}"
🚀Fly.io
- Região
iad(Supabase) ougru(BR) - Backend:
strategy=immediate, 1 máquina - Worker Temporal:
immediate(rolling panica) - Migrations no
release_command - PG:
fly proxy 15432:5432+ psql NEXT_PUBLIC_*via[build.args]
🗄️Supabase / PG
- pgx/v5, backend como service_role (bypassa RLS)
- RLS em tabelas tenant-scoped
migrations/<ts>_<desc>.sqlidempotentes- DATABASE_URL direto 5432 (não pooler)
sslmode=requiresempre- pg_dump dentro do container do supabase
🔐Credenciais & K8s
pass show client/env/key→ env var- Nunca echo;
unsetdepois - kubectl: verificar contexto ANTES
- Nunca flag
-wwatch - GitOps: ArgoCD + GitLab CI
- Finalizers: delete + patch
finalizers:[]
🏗️Terraform / Terragrunt
- Wrapper YAML é o padrão: muda infra editando manifest, não HCL
- Nunca
terraform applyna mão — só via task - Módulos em repo separado, ref por git tag
- 1 state por componente por env (S3 + DynamoDB)
- Promoção: bump
module_refdev → qas → prd - Lint: tflint + checkov antes do apply
📋Ansible
- Inventário YAML, nunca INI — groups +
children - Módulo declarativo > shell (apt, sysctl, systemd)
- Shell só com
creates:/changed_when - Tags em todo bloco funcional
- Secrets via pass no deploy, zero hardcode
- Health:
register + until + retries, nunca sleep
☁️Cloudflare
- DNS proxied (orange) quando há Access
- SSL Full, não Flexible (origin com cert LE)
- Zero Trust Access: OTP email, criado via API
- Workers:
wrangler deploy --containers-rollout=immediate - WARP/tunnel pra RDS em subnet privada
- Debug:
wrangler tail --format=pretty
AIOX Spec-Driven Development
Specs antes de código. Paths exatos — nunca PRD.md, nunca docs/specs/.
docs/ ├── prd.md # Goals · FR/NFR · Assumptions · Epics ├── architecture.md # Tech Stack table · Data Models · DDL · Workflows ├── stories/ │ ├── {epic}.{story}.{slug}.md # Status · Executor · AC · Tasks · Dev Notes │ └── DEPENDENCY-GRAPH.md └── runbooks/<topic>.md
📋Story — seções na ordem exata
Status → Executor Assignment → Story ("As a…") → Acceptance Criteria → Tasks/Subtasks → Dev Notes (contexto completo; dev nunca relê architecture.md) → Change Log → Dev Agent Record → QA Results.
⚖️Regras de execução
executor ≠ quality_gate— sempre- Story atômica: começa e termina antes da próxima
- Ordem do grafo de dependências, nunca pular
- Status e Tasks atualizados em tempo real
- Paralelismo só sem dependência mútua
Stack Padrão
Escolhas default. Desviar exige justificativa na arquitetura.
| Camada | Escolha | Área |
|---|---|---|
| Backend | Go 1.26 · chi v5 · pgx/v5 · slog | go |
| Workflows | Temporal | go |
| DB | PostgreSQL 15+ (Supabase ou self-managed) | ops |
| Auth | Supabase JWT | gofe |
| Frontend | Next.js 16 · React 19 · Tailwind 4 · pnpm | fe |
| FE testes | vitest + testing-library + jsdom | fe |
| STT / LLM | Groq Whisper V3 · Claude (OpenRouter/Anthropic) | go |
| Billing / Email | Stripe (API nativa, sem SDK) · Resend | go |
| Observabilidade | Sentry + slog JSON | ops |
| Deploy | Fly.io (iad/gru) · CF Pages · K8s | ops |
| Imagens | chainguard/static (0 CVEs) | ops |
| Automação | Taskfile + scripts/ | ops |
| IaC / GitOps | Terraform/Terragrunt · Helm · ArgoCD · GitLab CI | ops |
Bootstrap de Projeto Novo
Checklist na ordem. Specs primeiro, código depois.
1️⃣Specs & estrutura
docs/prd.md+architecture.md+stories/Taskfile.yaml+scripts/no dia zero- Backend: cmd/ domain/ ports/ adapters/ internal/config
- Frontend: (auth)/(dashboard),
lib/api.ts, providers
2️⃣Infra & gates
supabase/migrations/+ RLS- Dockerfile chainguard + fly.toml por app
- CLAUDE.md na raiz: comandos + gotchas de produção
- Testes como deps de build/deploy; gates de cobertura ligados
Specs Completas
Conteúdo integral de cada llms.txt, embutido na página. Copie direto ou abra o arquivo.