↑ ↓ para mover · Enter para abrir · Esc para fecharToque em um resultado

Arquitetura
skill · classe design · opus

domain-modeling

Modela o agregado, as invariantes, as portas e os eventos a partir do caso de uso.

skill · designopusescreve 10-dominio.mdsó dentro de docs/use-cases/UC-*/**
§ o arquivo que ela escreve

10-dominio.md, bloco a bloco

Um parcial real: UC-001-create-customer, no bank-app, em trechos. Passe o mouse ou clique num bloco para ver o que a skill fixa ali. As seções do arquivo também são chips: clique em um para ir até ela.

bank-app/docs/use-cases/UC-001-create-customer/10-dominio.md

UC-001 · Domain and application

Partial of docs/use-cases/UC-001-create-customer/. Owner: domain-modeling. Inherits the canonical names from 00-caso-de-uso.md — doesn't reinvent them. Contains no code. Form references in .claude/skills/domain-modeling/templates/*.java.example.
FieldValue
Mother spec00-caso-de-uso.md
AggregateCustomer
Divergences from the mother specnone — the open rows of its component table are closed here: name stays String, birthDate stays LocalDate, today's date comes from an injected java.time.Clock

Package base: dev.nerviz.bankapp. Paths below are relative to src/main/java/dev/nerviz/bankapp/.

## 1 · Aggregate and value objects

Aggregate root: Customer. Boundary: the customer alone — no reference to another aggregate.

FieldTypeWhy this type
idCustomerIdValue object over UUID (v7). Prevents passing another aggregate's id in its place
nameStringFree text — counter-catalog of @.claude/rules/value-objects.md. Trim, not blank and 2 to 120 characters are invariants of Customer
securityNumberSecurityNumberFormation rule (exactly 11 digits) and own behaviour (masked()) — criteria 1 and 4
birthDateLocalDatejava.time is already an immutable value with a unit; not wrapped (value-objects.md § Numbers). The age rules depend on today and live in Customer.register
registeredAtInstantCreation instant, from the injected Clock

Value objects

VOWrapsOwn invariantFactory
CustomerIdUUIDnot nullCustomerId.of(UUID)
SecurityNumberStringnot null; exactly 11 characters, each 0–9; no check-digit validation (mother spec, user's decision). of trims surrounding whitespace only — no mask removal: punctuation is rejected, not strippedSecurityNumber.of(String)

SecurityNumber exposes value() (the 11 digits, for persistence mapping) and masked() (********* followed by the last 2 digits). Its toString() returns masked(), so a SecurityNumber concatenated into a log line or an exception message never prints the full value.

All record, immutable, validation in the compact constructor. Shape: templates/ValueObject.java.example.

… cortado aqui, o resto está no arquivo

## 2 · Invariants

Exception family: NEW — five classes in the domain.exception package: DomainException (abstract, errorCode required), NotFoundException, ValidationException, BusinessRuleViolationException, ConflictException. Shapes in templates/DomainException.java.example and the four typed ones. NotFoundException is unused by this case and still created: the family is created once, whole.

#InvariantWhere it's enforcedExceptionerrorCode
1id is presentCustomer compact constructorValidationExceptionCUSTOMER_ID_REQUIRED
2name is present and not blank after trimmingCustomer compact constructorValidationExceptionCUSTOMER_NAME_REQUIRED
3name, trimmed, has 2 to 120 characters; the trimmed value is storedCustomer compact constructorValidationExceptionCUSTOMER_NAME_LENGTH
4securityNumber is presentSecurityNumber compact constructor / Customer compact constructorValidationExceptionSECURITY_NUMBER_REQUIRED
5securityNumber is exactly 11 digits 0–9SecurityNumber compact constructorValidationExceptionSECURITY_NUMBER_INVALID
6birthDate is presentCustomer compact constructorValidationExceptionBIRTH_DATE_REQUIRED
7birthDate is not after todayCustomer.registerValidationExceptionBIRTH_DATE_IN_FUTURE
8completed age at most 130: birthDate.plusYears(131) is after todayCustomer.registerValidationExceptionBIRTH_DATE_TOO_OLD
9strictly over 18: birthDate.plusYears(18) is before today (equal is rejected)Customer.registerBusinessRuleViolationExceptionCUSTOMER_UNDERAGE
10registeredAt is presentCustomer compact constructorValidationExceptionREGISTERED_AT_REQUIRED
11securityNumber is unique in the systemoutside the aggregate — CreateCustomerUseCase checks through CustomerRepository.existsBySecurityNumber; the unique constraint closes the race and the adapter translates its violationSecurityNumberAlreadyRegisteredException (extends ConflictException)SECURITY_NUMBER_ALREADY_REGISTERED

Order inside register: 7, then 8, then 9 — a future date reports itself as such, not as underage. plusYears on 29 February yields 28 February in a non-leap year (mother spec).

… cortado aqui, o resto está no arquivo

## 3 · Ports

Input — clean architecture: no interface. The concrete use case is the input boundary.

application/usecase/customer/CreateCustomerUseCase.java

class CreateCustomerUseCase
    CreateCustomerUseCase(CustomerRepository customerRepository, Clock clock)
    CustomerId create(CreateCustomerCommand command)

create:

  1. builds SecurityNumber.of(command.securityNumber()) (invariants 4-5);
  2. customerRepository.existsBySecurityNumber(securityNumber) → true raises
  3. Customer.register(new id, command.name(), securityNumber, command.birthDate(), clock)
  4. customerRepository.save(customer) and returns its id().

The transaction opens and closes on this method (@.claude/rules/architecture-ddd.md § Application) — the annotation lives on this application-layer class. Constructor injection, private final fields. Throws ValidationException, BusinessRuleViolationException and SecurityNumberAlreadyRegisteredException.

Validating the format (step 1) before the uniqueness lookup keeps a malformed number from reaching the database query.

Command — application/usecase/customer/CreateCustomerCommand.java

… cortado aqui, o resto está no arquivo

## 4 · Events

none — the mother spec fixes no publication: no other system needs to learn that a customer was created. No CustomerCreated is designed; a future case that needs it adds it in its own ## Impact on approved use cases.

## 5 · Components to create

Refines the 00-caso-de-uso.md rows marked Detailed by: domain-modeling.

FileTypeState
domain/model/CustomerId.javarecord VONEW
domain/model/SecurityNumber.javarecord VONEW
domain/model/Customer.javarecord aggregateNEW
domain/exception/DomainException.javaabstract classNEW
domain/exception/NotFoundException.javaclassNEW
domain/exception/ValidationException.javaclassNEW
domain/exception/BusinessRuleViolationException.javaclassNEW
domain/exception/ConflictException.javaclassNEW
domain/exception/SecurityNumberAlreadyRegisteredException.javaclass, extends ConflictExceptionNEW
application/usecase/customer/CreateCustomerCommand.javarecordNEW
application/usecase/customer/CreateCustomerUseCase.javaclassNEW
application/port/CustomerRepository.javainterfaceNEW

Requirement for the wiring, not a domain class: a java.time.Clock bean (Clock.systemUTC()) in infrastructure/config/ClockConfig.java — NEW, none exists. Written by the executor with the configuration; recorded here because the use case's constructor needs it.

## Design patterns

none — no force in the spec, no symptom on disk. The static factories register / rehydrate are the naming rule's creation convention (@.claude/rules/naming.md § Methods), not a catalog pattern; nothing in the mother spec enumerates variants or rules per type, and src/main/java holds no domain or application class yet.

## Impact on approved use cases

none — UC-001 is the first case.

Abrir o arquivo completo no GitHub →
§ comportamento

O que lê, escreve e recusa

O contrato da própria skill, do SKILL.md, no texto original.

Class

design — the territory is skill_classes.design in @.claude/schemas/extensions.json and ArchHook.java guard enforces it. Writes inside the use case folder and nothing else; a write anywhere outside is refused with exit 2.

Reads

docs/use-cases/UC-NNN-<slug>/00-use-case.md (mandatory — stops without it), @.claude/rules/architecture-ddd.md (Domain and Application sections), @.claude/rules/value-objects.md (criterion for which field becomes a value object), @.claude/rules/naming.md, @.claude/rules/error-handling.md, @.claude/rules/code-quality.md, @.claude/rules/logging.md (which fields to flag as masking candidates), @.claude/rules/spec-diagrams.md (the diagrams of block 1) with references/mermaid-class-and-state.md, @.claude/rules/authorization.md § Boundary (only when Access is the owner — step 4c), @.claude/rules/spec-external-facts.md (an identifier or value of another system that a domain name or invariant states carries a source), and the active blueprint's packages.map.

Writes

docs/use-cases/UC-NNN-<slug>/10-domain.md. Only that file.

Does not write Java code

The classes in domain/ and application/ come from the executor agent — the exception family included: this skill owns the shape (the templates/ exemplars) and the state (NEW or REUSE, in the partial), not the writing. Does not touch 00-use-case.md (use-case-design), the other partials, or .claude/rules/**.

Does not collide with `gof-design-patterns`

That skill owns the catalog and, invoked standalone, refactors code that already hurts; this one decides which catalog row shapes the domain of the case being designed, and writes the decision into the partial — step 5b. Different artifacts, one owner of each.

Does not

decide persistence, mapping, or transport technology — 20-persistence.md and 30-rest.md have their own owners.

Fonte: SKILL.md § Contract, no nerviz e4cae27.

§ guard e hook

O que o guard faz com ela

design é a classe da skill. O ArchHook abre uma fase quando a skill é chamada e confere cada escrita contra o território da classe. O texto à direita é o do próprio hook.

write_allow da classe design

  • ✓docs/use-cases/UC-*/**
  • ✓docs/use-cases/BACKLOG.md
  • src/**: migrations e classes são do executor
  • docker-compose.yml: arquivo de outra classe
  • caso de uso já aprovado: as specs ficam congeladas

A recusa sai com código 2 e a mensagem volta para o modelo.

PreToolUse  Skill(domain-modeling)
  audit call                       exit 0
  guard call                       exit 0
# a skill of another class replaces the phase
# write_allow: docs/use-cases/UC-*/**, docs/use-cases/BACKLOG.md
§ orquestração

Onde ela fica no trilho

Cada cartão é um passo do /new-feature; a seta leva o parcial que um passo entrega ao seguinte. Passos tracejados só rodam quando o caso de uso precisa.

/new-feature-implement Quem lê o parcial depois

Depois da aprovação, o /new-feature-implement faz o executor construir o código. A spec é consolidada por referência e vale onde ela e um parcial divergem; o parcial é lido, por seção, para o detalhe.

10-dominio.mddocs/use-cases/UC-NNN-…/
lido por seção, para o detalhe
java-spring-boot-developeragent · executor
escreve o código
src/**desenha um caso de uso numa spec, não escreve código
← voltar às cadeias