AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Architecture Ddd Clean Arch

skill-gianverdum-ai-dev-skillset-architecture-ddd-clean-arch · by gianverdum

Desenvolvimento e edição de software seguindo DDD + Clean Architecture (default quando não há padrão local nem pedido explícito por hexagonal). Use sempre que o agente for desenvolver nova funcionalidade, alterar código existente, corrigir bugs, refatorar, criar testes, criar módulo, extrair bounded context, ou editar projeto que deva preservar separação de camadas, regras de domínio e dependênci…

No reviews yet
0 installs
22 views
0.0% view→install

Install

$ agentstack add skill-gianverdum-ai-dev-skillset-architecture-ddd-clean-arch

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-gianverdum-ai-dev-skillset-architecture-ddd-clean-arch)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Architecture Ddd Clean Arch? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

DDD + Clean Architecture

Use esta skill sempre que for desenvolver algo novo ou editar algo já desenvolvido em estilo Clean Architecture.

Precedência entre Clean Architecture e Hexagonal

A escolha NÃO é por preferência do agente. Siga esta ordem:

  1. Padrão do projeto existente — se o repositório já tem layout Clean Arch (domain/, application/, interface/, infrastructure/), preserve. Se o repo já é hexagonal (ports/, adapters/in, adapters/out), use a skill architecture-ddd-hexagonal em vez desta.
  2. Solicitação do usuário — quando o usuário pedir "hexagonal", "ports and adapters" ou "hex", aplique architecture-ddd-hexagonal. Quando pedir "clean architecture" ou similar, aplique esta skill.
  3. Default — na ausência de padrão local e de pedido explícito, use esta skill (Clean Architecture).

Nunca misture os dois layouts no mesmo módulo.

Princípios

  • Preserve o domínio como centro da aplicação.
  • Mantenha regras de negócio independentes de frameworks, banco de dados, filas, HTTP, UI e serviços externos.
  • Faça dependências apontarem para dentro: camadas externas podem conhecer camadas internas, mas camadas internas não devem depender de detalhes externos.
  • Modele comportamento de domínio no domínio, não em controllers, handlers, repositories ou componentes de interface.
  • Prefira nomes da linguagem ubíqua do projeto aos nomes técnicos genéricos.
  • Nomes de modulo, pacote e diretorio refletem o DOMINIO, nao a tecnologia de entrega nem a interface implementada. Sufixos como _cli, _api, _web, _rest, _grpc, _gui, _service, _lib ou seus equivalentes idiomaticos NAO entram no nome do pacote/modulo; ficam apenas no nome publicado do projeto (ex.: pyproject.toml [project] name, package.json name, artefato Maven/NuGet) quando precisar distinguir entregas. Exemplos: pacote Python calculadora publicado como calculadora-cli; modulo Go payments exposto via cmd/payments-api/; crate Rust auth publicado como auth-cli. O fato de a entrega atual ser CLI, API ou GUI nao muda o nome do modulo: o dominio e estavel, a interface e substituivel.
  • Quando houver dúvida sobre nomenclatura de arquivos, pacotes, módulos, classes ou estrutura inicial, consulte a rule da linguagem em .agents/rules e preserve o padrão local se ele existir.
  • Identificadores de codigo (variaveis, funcoes, classes, modulos, pacotes, testes, logs) seguem a rule coding-language-english: ingles e o idioma exclusivo de codificacao, com excecoes apenas para termos intraduziveis do dominio. Mensagens voltadas ao usuario nao sao literais em outro idioma no codigo: ou estao em ingles como default, ou sao chaves de i18n.

Camadas e Pastas

Layout obrigatorio de um modulo em src//:

src//
  domain/              # entidades, domain services, eventos, regras e invariantes
  aggregates/          # aggregate roots (cada um em arquivo proprio)
  value-objects/       # value objects (cada um em arquivo proprio)
  application/         # casos de uso, ports, orquestracao
  infrastructure/      # adapters de saida (repositorios, clients HTTP, brokers)
  interface/           # adapters de entrada (CLI, HTTP, handlers)

Responsabilidade de cada pasta:

  • domain/: entities (sem identidade de aggregate root), domain services, eventos de dominio, regras e invariantes que nao se encaixam em um aggregate. Nao pertencem ao dominio: parsing textual (CLI args, JSON, XML, query string, formularios), serializacao/desserializacao, IO (arquivos, rede, banco, console), templates de apresentacao, manipulacao de AST. Esses detalhes vivem em interface (parsing/apresentacao) ou application (orquestracao). Dominio recebe valores ja tipados e validados.
  • aggregates/: cada aggregate root em arquivo proprio (aggregates/project.ts, aggregates/tenant.ts, aggregates/charge.ts). Aggregate root e classe com metodos, nao type/record mutavel por fora — veja "Modelagem Tatica".
  • value-objects/: cada VO em arquivo proprio (value-objects/task-id.ts, value-objects/money.ts, value-objects/billing-month.ts). Imutaveis, igualdade por valor, invariantes no construtor.
  • application/: casos de uso (em application/use-cases/.ts quando 5+), portas em application/ports/.ts, orquestracao, autorizacao de fluxo, transacoes.
  • infrastructure/: implementacoes de repositorios, gateways, clients externos, mensageria, persistencia. Adapters de saida.
  • interface/: controllers, rotas, presenters, views, serializers, forms, handlers de entrada. Adapters de entrada.

VOs de identidade compartilhados entre BCs (TenantId, UserId, TaskId) ficam em src/shared-kernel/value-objects/.ts, NAO dentro de um modulo especifico. Ver "Shared Kernel" em Modelagem Tatica.

Camadas Detalhadas

  • Domínio: entidades, value objects, domain services, eventos de domínio, regras e invariantes. Não pertencem ao domínio: parsing de string textual (CLI args, JSON, XML, query string, formulários), serialização/desserialização para formatos externos, IO (arquivos, rede, banco, console), templates de apresentação, manipulação de AST de linguagens externas, validação de formato de entrada. Esses detalhes vivem em interface (parsing/apresentação de entrada externa) ou application (orquestração e validação de entrada já estruturada). O domínio recebe valores já tipados e validados.
  • Aplicação: casos de uso, orquestração, portas/interfaces, transações e autorização de fluxo.
  • Infraestrutura: implementações de repositories, gateways, clients externos, mensageria, persistência e adapters.
  • Interface: controllers, rotas, presenters, views, serializers, forms e handlers de entrada.

Fluxo

  1. Entenda a intenção do usuário e identifique qual regra de negócio está sendo criada ou alterada.
  2. Leia a estrutura existente antes de editar e siga os padrões já usados no projeto.
  3. Se estiver criando software do zero ou uma funcionalidade sem estrutura clara, consulte a rule da linguagem para nomenclatura e layout base.
  4. Defina o módulo ou bounded context que vai receber a mudança.
  5. Localize a camada correta para a mudança.
  6. Se a mudança toca regra de negócio, implemente ou ajuste o domínio primeiro.
  7. Coloque orquestração de fluxo em casos de uso ou serviços de aplicação.
  8. Use portas/interfaces para dependências externas quando a camada interna precisar de algo de fora.
  9. Implemente detalhes técnicos apenas nas camadas externas.
  10. Adicione ou ajuste testes na camada mais próxima do comportamento alterado.
  11. Atualize a documentação do projeto ou módulo quando a mudança alterar estrutura, arquitetura, tecnologia ou comandos.

Estrutura Inicial

  • Mesmo em pedidos pequenos, não coloque regras de negócio em arquivos soltos na raiz do projeto.
  • Trate novas CLIs, serviços, bibliotecas e ferramentas como módulos com fronteira própria.
  • Quando não houver padrão existente, crie módulos de produção dentro de src/ com as três camadas mínimas obrigatórias: domain, application e interface (mais a estrutura de testes). As três são exigidas mesmo em CLIs e utilitários pequenos: a camada de aplicação não é opcional por "ser simples demais"; comece com um caso de uso fino que orquestra o domínio e ele evolui depois. Ajuste os nomes ao layout idiomático da stack quando a rule aplicável indicar outro padrão (ex.: cmd/ e internal/ em Go, src/main/java em Java).
  • Ajuste src/ ao padrão idiomático da linguagem quando a rule aplicável indicar outro layout de mercado, como cmd/ e internal/ em Go ou src/main/java em Java.
  • Entry points, comandos CLI, rotas e handlers pertencem à interface e devem delegar comportamento para aplicação ou domínio.
  • Manifests e arquivos de configuração podem ficar na raiz quando forem convenção da linguagem ou ferramenta.
  • Documente a responsabilidade do módulo e das camadas no README.md mais próximo, mantendo o texto enxuto.

Modelagem Tatica: Aggregate, Entity, Value Object

DDD distingue tres formas de modelar conceitos do dominio. Use a forma correta para cada um; misturar gera dominio raso (anemic) ou acoplamento errado.

Regras estruturais (onde cada coisa mora)

  • Aggregate root vive em src//aggregates/.ts (um arquivo por aggregate root).
  • Value Object vive em src//value-objects/.ts (um arquivo por VO).
  • Entity nao-root (filha de um aggregate) vive em src//aggregates/.ts JUNTO do root que a controla — entities filhas nao tem arquivo proprio fora do aggregate dono.
  • VOs de identidade compartilhados entre BCs (TenantId, UserId, TaskId) ficam em src/shared-kernel/value-objects/.ts na RAIZ de src/. NUNCA dentro de outro modulo (src//.../shared-kernel/ e DESVIO).
  • Domain services, errors, eventos: ficam em src//domain/.

Restricoes do shared-kernel

src/shared-kernel/ e estritamente para tipos compartilhados entre BCs — NAO e um modulo nem um BC. Conteudo permitido:

  • value-objects/ — VOs de identidade compartilhados (TenantId, UserId, TaskId).
  • errors.ts (opcional) — DomainError ou base de codigo de erro apenas como tipo/classe base reutilizavel, sem catalogo de mensagens nem regra de negocio.
  • event-types.ts (opcional) — tipos de evento de dominio compartilhados entre BCs (apenas o shape, sem handlers).

Conteudo PROIBIDO em shared-kernel (cada um e DESVIO):

  • shared-kernel/application/ — shared-kernel nao tem casos de uso, nao tem portas, nao tem helpers de busca cross-BC.
  • shared-kernel/infrastructure/ — shared-kernel nao tem repositorio, nao tem cliente HTTP, nao persiste nada.
  • shared-kernel/interface/ — shared-kernel nao tem CLI nem catalogo de mensagens.
  • shared-kernel/domain/.ts definindo state composto (Tenant & { clients }, ProjectManagementState) — state composto cross-BC e o monolito disfarcado. Cada BC tem seu proprio state.

Sinais de shared-kernel inchado (DESVIO):

  • shared-kernel/ ganhou application/, infrastructure/ ou interface/.
  • shared-kernel/domain/ tem mais que VOs + errors.ts + event-types.ts.
  • Tipos como State, Repository, Messages aparecem em shared-kernel.
  • Funcoes como findX, getX, loadX aparecem em shared-kernel/application.
  • Cada BC importa state composto (com filhos de outros BCs) do shared-kernel.

Quando shared-kernel cresce alem do permitido, o monolito foi renomeado, nao quebrado. Os "BCs" sao fachadas sobre o estado compartilhado.

Aggregate Root e dono da relacao com filhos

Aggregate root controla a colecao de seus filhos. A colecao e propriedade do root, manipulada por seus metodos:

// CERTO
export class Project {
  private constructor(
    public readonly id: ProjectId,
    private tasks: Map,    // colecao DENTRO do root
  ) {}

  createTask(taskId: TaskId, title: string, by: UserId): void {
    if (this.tasks.has(taskId)) throw new DomainError("task_already_exists");
    this.tasks.set(taskId, Task.create(taskId, title, by));
  }
}

Composite type externo ao aggregate, com filhos colados por fora, e DESVIO:

// ERRADO — composite externo
export type Project = ProjectAggregate & { tasks: Record };  // ❌

const project = ProjectAggregate.create(...) as Project;
project.tasks = {};                                                          // ❌ mutacao externa

Sintomas:

  • type X = XAggregate & { children: ... } em shared-kernel ou no modulo de outro BC.
  • Cast as X apos XAggregate.create(...) para "ganhar" o campo de filhos.
  • Mutacao da colecao (x.children = {}, x.children[id] = ...) fora dos metodos do root.

Quando o aggregate root nao e dono da colecao, o conceito "aggregate" foi desfeito — vira data record orquestrado externamente.

Proibicao absoluta: composite cross-BC

Nenhum modulo do repositorio, independentemente do nome (shared-kernel/, project-management/, core/, common/, state/, etc.), pode definir tipo composto que liga aggregates de mais de um BC:

// PROIBIDO em qualquer lugar do projeto
export type Tenant = TenantAggregate & { clients: Record };  // ❌
export type Client = ClientAggregate & { projects: Record }; // ❌
export type ProjectManagementState = { tenants: Record };    // ❌ composto cross-BC

A regra vale independentemente do modulo onde o composto for declarado. Renomear o monolito de shared-kernel para project-management/, core/, ou qualquer outro modulo de "tipos compartilhados" NAO resolve — continua sendo o anti-padrao "BCs cosmeticos sobre estado composto centralizado".

Padrao correto:

  • Aggregate root e dono da sua propria colecao (via metodo, dentro do root).
  • Cross-BC e feito por ID + porta. BC tenancy mantem Tenant puro (com sua propria colecao se houver, sem clients de outro BC). BC client-management mantem Client puro (com tenantId referenciando, nao Tenant composto). Quando BC X precisa de dado de BC Y, declara port em X e adapter ligando Y.
  • Persistencia: cada BC tem State = RecordId, Aggregate> proprio. O repositorio do BC carrega/persiste so o seu sub-state.

Sinais de DESVIO mecanico (gatilho objetivo):

  • grep -rn "& { .* Record }).
  • Existencia de qualquer *State que contem aggregates de mais de um modulo.

Modulo legitimo vs modulo monolito disfarcado

Modulo (BC) legitimo tem todas as caracteristicas abaixo:

  1. aggregates/.ts — pelo menos um aggregate root proprio.
  2. application/use-cases/.ts — pelo menos um caso de uso proprio do BC.
  3. application/ports/.ts — porta(s) de saida proprias quando o BC precisa de IO.
  4. infrastructure/.ts — implementacao das portas, NAO delegacao 100% a outro modulo.
  5. interface/cli.ts (ou adapter de entrada equivalente) com comandos do proprio BC, OU um README declarando que e BC de leitura/policy sem entrada propria (ex.: access-control).
  6. README.md declarando responsabilidade.
  7. Tests proprios (unit dos aggregates + integration + e2e quando expoe operacoes).

Modulo monolito disfarcado (DESVIO grave) tem o oposto: state composto cross-BC + helpers de busca cross-BC + porta retornando state composto + repositorio unico. Sintomas:

  • Tem application/.ts com helpers findX/getX/loadX que percorrem aggregates de outros BCs.
  • Tem application/ports/-repository.ts retornando state composto cross-BC.
  • Tem infrastructure/.ts persistindo tudo num arquivo/tabela unico.
  • NAO tem aggregates/ proprios — so define types compostos sobre aggregates de outros BCs.
  • NAO tem application/use-cases/ — so helpers.
  • NAO tem interface/cli.ts proprio — outros BCs delegam mensagens via ele.

Quando um modulo tem o segundo perfil (sem aggregates proprios, sem use cases proprios, com state composto e repo unico), ele e o monolito renomeado que sobrevive a regras anti-shared-kernel-inchado.

Isolamento de Estado por Bounded Context

Cada BC tem seu proprio state, repositorio e schema persistido. Compartilhar state composto via shared-kernel ou via repositorio unico transforma os "BCs" em fachadas cosmeticas sobre um monolito.

Regras objetivas:

  • A porta de repositorio de um BC retorna o State proprio (ex.: TenantState, ClientState, ProjectState), NUNCA um ProjectManagementState ou WholeState composto que mistura BCs.
  • O schema persistido de cada BC e arquivo/tabela/coleção proprio, nao compartilhado. Se a stack obriga arquivo unico (ex.: CLI com um JSON local), o arquivo carrega um envelope versionado com sub-objetos por BC, e cada repositorio le/grava SOMENTE a sua sub-arvore.
  • Adapter concreto de repositorio nao extende repositorio de outro BC nem do shared-kernel. class JsonTenantStateRepository extends JsonProjectManagementStateRepository {} (classe vazia herdando do shared) = DESVIO grave. Implemente o repositorio diretamente em /infrastructure/.
  • Adapter concreto que delega 100% das operacoes para outro repositorio (mesmo via composicao) tambem e DESVIO. Trocar `extends

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.