use-case-design
Transforma um pedido em um caso de uso: fronteira, fluxo e nomes canônicos.
00-caso-de-uso.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.
UC-001 · Create customer
Parent spec. Fixes the boundary and the names; doesn't detail any layer. Per-layer detail lives in this folder's partials, each with its own owner.
| Field | Value |
|---|---|
| Identifier | UC-001-create-customer |
| Date | 2026-10-07 |
| Trigger | customer creation, over HTTP — inbound REST adapter. The exact path and verb belong to rest-api-architect, in 30-rest.md |
| Access | public — anyone may call it, no caller identity required (business fact, user's answer). Mechanism, the permitAll reason and status belong to security-architect, in 32-seguranca.md |
| Side effects | 1 — INSERT into customers |
| External calls | none — no side effect reaches a system this service does not own |
| Publication | none — no other system needs to learn that a customer was created; no domain event is published by this case |
| Transaction | opens at the use case CreateCustomerUseCase, closes before the response |
| Repetition | repeating the request with the same security number must not create a second customer (business fact): one customer per security number, the repeat is a conflict. The mechanism — Idempotency-Key or none — is delegated to rest-api-architect |
| Concurrency | the uniqueness of the security number is arbitrated by a unique constraint on the stored value; no application-level lock. Two concurrent requests with the same number: one is created, the other is a conflict |
| Personal data | securityNumber (national identification number, 11 digits) and birthDate are personal data. They never appear in clear in logs — @.claude/rules/personal-data.md, @.claude/rules/logging.md. The response carries only a reference, so neither leaves the service in a response body |
| Active blueprint | clean-architecture-single-module |
## Trigger, payload, and response
In
| Field | Type | Required | Rule |
|---|---|---|---|
name | string | ✅ | leading and trailing whitespace trimmed; after trimming, not blank and 2 to 120 characters |
securityNumber | string | ✅ | exactly 11 numeric digits (0–9); no check-digit validation; unique in the system |
birthDate | date | ✅ | the customer's 18th birthday is strictly before today (a customer whose 18th birthday is today is rejected); the customer is not over 130 years old today; a date in the future is rejected |
How "today" and the anniversaries are computed:
- "Today" is the current calendar date taken from the application's clock, never from the
- The N-th birthday is
birthDateplus N calendar years. For abirthDateof 29 February, - Accepted when
birthDate + 18 years < todayandbirthDate + 131 years > today—
Out
Situations, not statuses. The HTTP code for each is rest-api-architect's decision.
… cortado aqui, o resto está no arquivo
## Flow
- The inbound adapter receives the request and validates the payload's shape.
- Translates it into the command
CreateCustomerCommand. - The use case
CreateCustomerUseCaseexecutes: checks through the outbound port - The outbound port
CustomerRepositorypersists it. A unique-constraint violation from a - The adapter translates the returned aggregate into the response — a reference only.
Nothing in this flow names annotations, columns, or framework types — that belongs to the partials.
## Components
State: NEW to be created · CHANGE already exists and changes · REUSE already exists and serves.
Paths relative to src/main/java/dev/nerviz/bankapp/ unless they start with src/.
… cortado aqui, o resto está no arquivo
## Invariants
| Rule | Guaranteed by | Who violates it |
|---|---|---|
securityNumber is exactly 11 numeric digits | the security number's creation | caller with letters, punctuation, or a different length |
securityNumber is unique in the system | check at the outbound port + unique constraint | second registration, or a race between two requests |
name, trimmed, is 2 to 120 characters and not blank | Customer's creation | blank or overly long payload |
| 18th birthday strictly before today | Customer's creation, against the clock's date | a minor, or a customer whose 18th birthday is today |
| completed age at most 130 | Customer's creation, against the clock's date | a typo such as 1825 instead of 1985 |
birthDate is not in the future | Customer's creation, against the clock's date | a typo, or a wrong date format interpreted |
Invariants live in the aggregate, never in the caller — @.claude/rules/architecture-ddd.md.
## Errors
| Situation | Kind |
|---|---|
| security number already registered | conflict with existing state |
| customer not strictly over 18 | business rule |
| security number not exactly 11 digits | validation |
| name blank or outside 2 to 120 characters | validation |
| birth date in the future, or age over 130 | validation |
| required field missing, or a date that does not parse | shape — rejected in the adapter, never reaches the domain |
Situations and kinds, never exception names or statuses. The exception class and errorCode belong to 10-dominio.md (@.claude/rules/error-handling.md); the HTTP mapping belongs to 30-rest.md.
## Expected tests
| Level | Target | Detailed by |
|---|---|---|
| unit | Customer: name trim and length, 11-digit security number, age boundaries (18th birthday yesterday / today / tomorrow, 29 February, age 130 / 131, future date) with a fixed clock | test-architect |
| unit | use case: security number already registered is a conflict, nothing persisted | test-architect |
| slice | controller: created with reference only, malformed payload, each validation error, under-age, conflict | test-architect |
| integration | CustomerRepositoryJpaAdapter against a real database, including the unique constraint | test-architect |
## Out of scope for this use case
Written down so nobody merges it back in by accident:
- Reading, updating and deleting a customer → their own use cases, their own triggers; not
- Check-digit validation of the security number (Brazilian CPF algorithm) → decided against:
- Publishing a
CustomerCreatedevent → no consumer exists; a future case that needs it adds - Authentication of the caller → the endpoint is public by decision.
## Impact on approved use cases
none — UC-001 is the first case.
## Implementation order
Derived from the Components table, in compile order.
- [ ] 1. domain typed fields (
SecurityNumber, and name / birth date if typed) - [ ] 2.
domain/model/Customer.java - [ ] 3. domain exceptions — named in
10-dominio.md - [ ] 4.
application/usecase/customer/CreateCustomerCommand.java - [ ] 5.
application/port/CustomerRepository.java - [ ] 6.
application/usecase/customer/CreateCustomerUseCase.java - [ ] 7.
src/main/resources/db/migration/V1__create_customers.sql - [ ] 8.
infrastructure/persistence/customer/(entity, Spring Data, adapter) - [ ] 9.
infrastructure/rest/(DTOs, mapper, controller, exception handler) - [ ] 10. tests for the levels above
- [ ] 11.
./mvnw clean verifygreen
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 the backlog, nothing else; a write anywhere outside is refused with exit 2, not reported.
Reads
@.claude/rules/architecture-ddd.md (Application section — where the transaction opens, what doesn't go in the signatures), @.claude/rules/naming.md, @.claude/rules/error-handling.md (the four kinds only — names belong to domain-modeling), @.claude/rules/api-graphql.md (§ Choosing the inbound protocol only, for an HTTP trigger), @.claude/rules/spec-diagrams.md (the sequence diagram and the flowchart) with references/mermaid-use-case-diagrams.md, @.claude/rules/spec-external-facts.md (every fact about another system carries a source), the active blueprint's packages.map and naming convention, and this skill's references/scope-boundary.md before counting effects.
Writes
docs/use-cases/UC-NNN-<slug>/00-use-case.md and appends to docs/use-cases/BACKLOG.md. Only those. The 10- through 40- partials belong to the layer skills; the consolidated UC-NNN-spec.md belongs to the /new-feature orchestrator.
Owns
the use case number and slug. No other piece assigns them.
Shares one sequence, with one other named writer
BL-NN is assigned here when a split appends a backlog row, and by /new-feature's consolidation when a partial defers something to the backlog. Those two, never a third: a design skill that appended its own row would compute "highest plus one" against the same file in the same run and issue a duplicate.
Does not
edit an approved spec (status: approved, implemented or implemented-blocked) — reads it as a contract, and records the needed change in its own impact section.
Does not
write code, tests, migrations, or OpenAPI, and never writes under src/. Doesn't touch the inbound REST adapter — the package the blueprint's packages.map gives that role (rest-api-architect) —, the domain or application (gof-design-patterns, domain-modeling), nor .claude/rules/**. Doesn't weigh a storage technology: records the storage family and the search engine the request states or the user answers.
Does not
reproduce rules. Cites by path; what the rule already says isn't repeated in the spec.
Also carries
examples/ — twelve complete 00-use-case.md fixtures for testing /new-feature and java-spring-boot-developer, indexed in examples/README.md. Meta-repo documentation, not this skill's runtime output: the export manifest keeps only SKILL.md, templates/ and references/, so this directory does not travel.
Fonte: SKILL.md § Contract, no nerviz e4cae27.
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 executordocker-compose.yml: arquivo de outra classecaso de uso já aprovado: as specs ficam congeladas
A recusa sai com código 2 e a mensagem volta para o modelo.
PreToolUse Skill(use-case-design) 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
PreToolUse Write(docs/use-cases/UC-005-record-kyc-verdict/00-caso-de-uso.md) guard write exit 0 PostToolUse audit file exit 0
PreToolUse Write(docker-compose.yml) guard write exit 2 ❌ `use-case-design` is class `design` — docker-compose.yml is outside its territory. write_allow: docs/use-cases/UC-*/**, docs/use-cases/BACKLOG.md Put the content in the spec as a code block, or finish the run and invoke the skill that owns this path. If the path is legitimately this skill's, widen skill_classes.design in .claude/schemas/extensions.json — retrying will not help.
# UC-005-record-kyc-verdict-spec.md: status: approved PreToolUse Edit(docs/use-cases/UC-005-record-kyc-verdict/00-caso-de-uso.md) guard write exit 2 ❌ UC-005-record-kyc-verdict is approved — its specs are immutable. Record the change in the new use case's "Impact on approved use cases" section, and the one-line entry in UC-005-record-kyc-verdict/CHANGELOG.md, which stays writable.
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 orchestrator · opus/new-feature-implement Quem lê o parcial depoisDepois 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.