Organizada por módulo temático, na ordem em que os conceitos foram introduzidos. Itens tracejados ainda não têm lição escrita — ver a missão por trás desta trilha e o roadmap completo em NOTES.md (seção "Roadmap: Clean Architecture").
Injeção de Dependência, o Dependency Inversion Principle, a Regra de Dependência, as quatro camadas, e a comparação com MVC/Active Record.
Satisfação implícita, a convenção de onde declarar a interface, por que isso facilita testes, e a pegadinha do nil.
go.mod, a relação entre diretório e pacote, caminhos de import, o diretório internal, e o que Go não dita sobre estrutura de pastas.
Domínio, use case, repositório fake para teste, implementação real e main.go — as três lições anteriores num projeto pequeno que compila e roda.
Por que a estrutura de pastas de um projeto deveria anunciar o que ele faz (aprovação de pedidos), não o framework/banco que ele usa — revisitando a árvore de aprovador-pedidos, que já grita domínio desde a Lição 4.
RejeitarPedido revela que o domínio nunca teve estado explícito — StatusPedido com iota, uma regra de idempotência em Pedido.Rejeitar(), e por que reaproveitar PedidoRepository (em vez de segregar de novo) é a decisão correta desta vez.
A escrita em pedido_eventos (Lição 12) sempre foi decidida escondida dentro do adapter Postgres — extraída para domain.PedidoAprovado/PedidoRejeitado e uma interface PublicadorDeEventos pequena, sem framework, com Postgres e log como dois assinantes reais.
Adicionando ConsultarPedido ao projeto e decidindo, com o vocabulário de ISP da Lição 24, se a nova operação entra em PedidoRepository ou vira uma interface segregada — do domínio ao adapter HTTP, com erro sentinela traduzido em cada camada.
Nomeia a regra de Uncle Bob sobre dados cruzando fronteiras (nunca uma Entity), reconhecendo que requisicaoPedido/respostaPedido/respostaConsultaPedido já são DTOs desde a Lição 15 — com um experimento mental sobre mass assignment sem eles.
Uncle Bob nomeia o que este workspace chama de usecase.Executar como um Interactor satisfazendo um Input Boundary, com um Output Boundary do outro lado. Mapeamento direto para AprovarPedido/ConsultarPedido/RejeitarPedido, sem mudar código.
Substituindo o repositório em memória por PostgreSQL via database/sql e o driver pgx, sem tocar em domain, usecase ou http — tradução de erros, schema mínimo e teste de integração separado do teste de unidade.
Uma tabela pedido_eventos exige duas escritas relacionadas em Salvar — resolvido com BeginTx/Commit/Rollback, defer tx.Rollback() mesmo após Commit, e isolamento READ COMMITTED, sem alterar a interface PedidoRepository.
DATABASE_URL lido sem validação desde a Lição 11, e porta HTTP hardcoded desde a Lição 15 — um struct Config centralizado em internal/config, validado como a primeira linha de main() (fail fast), distinguindo o que nunca deveria ter default do que pode.
AprovarPedido passa a consultar um serviço externo de score de crédito antes de aprovar — porta ConsultaDeScore declarada em usecase, adapter net/http idiomático em internal/scoreapi, timeout via context (Lição 26), DTO na fronteira de entrada (Lição 9), e teste com httptest.Server sem rede real.
Um Interface Adapter HTTP real (handler, JSON, httptest) chamando o use case da Lição 4, com diagrama de fluxo da requisição por todas as camadas.
Substituindo o roteamento manual (strings.TrimPrefix) pelos padrões de rota com método e {wildcard} da stdlib, com 404/405 automáticos — mudança isolada ao adapter HTTP, sem tocar em usecase, domain, logging ou validacao.
error vs. panic como dois mecanismos com propósitos diferentes, e um middleware RecuperarPanico envolvendo o ServeMux inteiro com defer/recover e stack trace — o mesmo padrão de decorator da Lição 19, aplicado a http.Handler.
Expondo Status (um iota) como texto legível no JSON de ConsultarPedido — um ConsultarPedidoPresenter produzindo um pedidoViewModel, com diagramas do fluxo completo banco→JSON e da régua Presenter vs. DTO simples.
Onde colocar logging e validação sem tocar no use case: extraindo uma interface do próprio AprovarPedido e empilhando decorators por fora, montados manualmente em main.go — quando vale a pena e quando é over-engineering.
ConsultarVariosPedidos dispara uma goroutine por ID e reúne resultados por um channel, com sync.WaitGroup e go test -race — o mesmo ctx da Lição 26 cancelando a leva inteira de uma vez quando o cliente desiste.
PodeAprovarAutomaticamente tinha um único teste desde a Lição 4, sem cobrir a fronteira exata do limite — reescrito como tabela de casos com t.Run, revelando também um terceiro caso esquecido em Pedido.Rejeitar().
Formatação não-opcional (gofmt/goimports), um bug real de %d vs %s pego por go vet sem quebrar a compilação, golangci-lint como padrão de mercado, e onde cada ferramenta entra num pipeline de CI típico.
Um teste comum (`go test`) usando `go list -deps` para falhar se `domain` algum dia importar outra camada — avaliado contra o go-cleanarch (sem commits desde 2021) antes de optar por um teste próprio, sem dependência nova.
Os quatro princípios de SOLID que ficaram fora da Lição 1, cada um ancorado em código real do projeto — com antes/depois de violações escritas de propósito.
Os três use cases têm assinaturas de Executar diferentes — generics (Go 1.18+) permitem um único LoggerDecorator[E, S] genérico em vez de três structs quase idênticas, com struct{} cobrindo o caso sem retorno de dado.
r.Context() propagado do handler HTTP até QueryRowContext/ExecContext no adapter Postgres, com um timeout explícito via context.WithTimeout — cancelamento e prazo atravessando as mesmas camadas que a Regra de Dependência já organiza.
ConsultarVariosPedidos evolui de uma goroutine por ID para um número fixo de workers lendo de um channel de trabalho — close(trabalho) só pelo remetente, e uma alternativa mais simples com semáforo via chan struct{}.
REP, CCP, CRP, ADP, SDP e SAP mapeados sobre os sete pacotes de aprovador-pedidos — a tensão entre os três princípios de coesão, e por que domain é ao mesmo tempo o pacote mais estável e o mais abstrato do projeto.
respostaPedido ganha o Score da Lição 14 sem quebrar quem já chama a API — mudança aditiva vs. destrutiva, a armadilha do zero value em Go, versionamento por data (Stripe) ou por URL, depreciação e um teste de contrato sobre o JSON bruto.
REP/CCP/CRP (Lição 28) como critério de prontidão para dar a um pacote seu próprio go.mod, a mecânica da replace directive, e por que nenhum dos oito pacotes de aprovador-pedidos se qualifica hoje — sem entrar em microsserviços ou deploy.
gofmt/vet/lint (Lição 22), go test -race (Lição 20), o teste de conformidade arquitetural (Lição 23) e o teste de contrato (Lição 29) num pipeline real de GitHub Actions, com ordem de execução por custo e o que cada estágio bloqueia.