@polymorphism-tech/morph-spec 9.3.0 → 9.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/README.md +2 -2
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/MORPH.md +23 -33
- package/framework/agents.json +10 -9
- package/framework/docs/CLI.md +3 -3
- package/framework/evals/review-checklist.md +1 -1
- package/framework/hooks/README.md +3 -2
- package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -15
- package/framework/hooks/claude-code/core/comment-guard.js +1 -0
- package/framework/hooks/claude-code/core/conventional-commit.js +57 -0
- package/framework/hooks/claude-code/core/denylist.json +63 -1
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +0 -8
- package/framework/hooks/claude-code/core/gate-guard.js +0 -8
- package/framework/hooks/claude-code/core/loop-detect.js +0 -3
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +2 -1
- package/framework/hooks/claude-code/core/protect-spec-files.js +0 -7
- package/framework/hooks/claude-code/core/validate-completion.js +0 -4
- package/framework/hooks/claude-code/core/worktree-context.js +0 -2
- package/framework/hooks/claude-code/statusline.py +3 -44
- package/framework/hooks/shared/build-check.js +12 -19
- package/framework/hooks/shared/command-tokens.js +17 -0
- package/framework/hooks/shared/comment-rules.js +11 -1
- package/framework/hooks/shared/hook-response.js +0 -4
- package/framework/hooks/shared/payload-utils.js +1 -35
- package/framework/hooks/shared/phase-utils.js +0 -12
- package/framework/hooks/shared/slice-progress.js +0 -2
- package/framework/hooks/shared/state-reader.js +0 -19
- package/framework/hooks/shared/telemetry-logger.js +1 -1
- package/framework/rules/csharp-standards.md +5 -3
- package/framework/rules/dotnet-templates.md +2 -2
- package/framework/rules/frontend-standards.md +1 -2
- package/framework/rules/nextjs-standards.md +10 -8
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-machine/SKILL.md +2 -2
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +3 -3
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +87 -37
- package/framework/standards/STANDARDS.meta.json +41 -15
- package/framework/standards/architecture/code-comments.md +1 -1
- package/framework/standards/architecture/engineering-lens.md +100 -0
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +7 -9
- package/framework/standards/backend/dotnet/analyzers.md +59 -0
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -12
- package/framework/standards/frontend/admin-app/data-table.md +1 -3
- package/framework/standards/frontend/admin-app/page-structure.md +8 -4
- package/framework/standards/frontend/nextjs/app-router.md +3 -4
- package/framework/standards/frontend/nextjs/components.md +2 -15
- package/framework/standards/frontend/nextjs/data-fetching.md +2 -3
- package/framework/standards/frontend/nextjs/lint.md +141 -0
- package/framework/standards/frontend/nextjs/motion-patterns.md +2 -7
- package/framework/standards/frontend/nextjs/naming-conventions.md +1 -2
- package/framework/standards/frontend/nextjs/nextjs-patterns.md +5 -7
- package/framework/standards/frontend/nextjs/project-structure.md +3 -2
- package/framework/standards/frontend/nextjs/state-management.md +6 -7
- package/framework/templates/README.md +4 -5
- package/framework/templates/REGISTRY.json +21 -516
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +54 -56
- package/package.json +3 -2
- package/src/commands/project/worktree.js +1 -1
- package/src/commands/state/archive.js +1 -1
- package/src/commands/state/finish.js +1 -1
- package/src/core/paths/output-schema.js +0 -9
- package/src/core/state/feature-identity.js +0 -2
- package/src/core/state/state-manager.js +1 -169
- package/src/core/templates/template-registry.js +1 -43
- package/src/core/templates/template-renderer.js +0 -23
- package/src/dashboard/app/lib/format.js +0 -7
- package/src/dashboard/app/lib/phases.js +0 -7
- package/src/dashboard/scanner/activity-scanner.js +0 -4
- package/src/lib/ai/ai-project-scan.js +1 -6
- package/src/lib/graph/graphify-runtime.js +0 -1
- package/src/lib/mutation/snapshot.js +1 -5
- package/src/lib/risk-detector.js +0 -5
- package/src/lib/stack/stack-profile.js +0 -4
- package/src/lib/stack/stack-scan.js +18 -9
- package/src/lib/tasks/eval-node.js +1 -7
- package/src/lib/validators/validation-runner.js +0 -43
- package/src/lib/validators/verify-runner.js +18 -2
- package/src/utils/agents-installer.js +12 -19
- package/src/utils/claude-settings-manager.js +0 -28
- package/src/utils/file-copier.js +0 -53
- package/src/utils/hooks-installer.js +1 -1
- package/framework/hooks/shared/activity-logger.js +0 -131
- package/framework/standards/frontend/design-system/naming.md +0 -68
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +0 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +0 -100
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +0 -90
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +0 -84
- package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +0 -44
- package/framework/templates/meta-prompts/validators/checkpoint-validator.md +0 -107
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +0 -94
- package/src/commands/validation/index.js +0 -2
- package/src/lib/validators/code-budget/index.js +0 -2
- package/src/lib/validators/contracts/index.js +0 -1
- package/src/lib/validators/nextjs/index.js +0 -1
- package/src/lib/validators/packages/index.js +0 -1
- package/src/lib/validators/reuse/index.js +0 -2
|
@@ -4,7 +4,7 @@ description: Guia a criação de uma landing page nova ponta-a-ponta a partir do
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando for iniciar um novo projeto de LP com o template Umbraco genérico
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ description: Migra uma landing page existente (React/Vite, Next.js estático ou
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando o usuário pedir "use /migrate-lp-to-umbraco {projeto}" ou descrever a necessidade de migrar uma LP para Umbraco
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ description: Executa as fatias do plano de uma feature morph-spec — dispatch p
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use com o gate do plano aprovado, em "use /morph-apply {feature}" ou "implementar feature"
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-apply
|
|
@@ -4,7 +4,7 @@ description: ADW cirúrgico de hotfix — resolve uma queda/bug crítico de prod
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando chegar "/morph-hotfix {feature}", quando a morph-plan rotear o pedido como workType hotfix, ou quando o usuário disser "produção caiu / hotfix / urgente" a respeito de um incidente
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-hotfix
|
|
@@ -4,7 +4,7 @@ description: Cuida da RAM e da CPU da máquina enquanto o morph-spec trabalha
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando a máquina estiver lenta ou sem RAM, um comando pesado esperou ou foi recusado pela fila, sobrou worktree de sub-agent, ou vários sub-agents pesados vão rodar em paralelo
|
|
6
6
|
user-invocable: false
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-machine
|
|
@@ -43,4 +43,4 @@ Limites: não cobre `run_in_background`, PowerShell nem comando fora da lista; u
|
|
|
43
43
|
## Referências
|
|
44
44
|
|
|
45
45
|
- `.morph/framework/CLI.md` — `### heavy`, `### worktree reap`, `### doctor --procs` e `### worktree.root`.
|
|
46
|
-
- `MORPH.md` §2.2 (worktrees) e a cláusula
|
|
46
|
+
- `MORPH.md` §2.2 (worktrees) e a cláusula PROCESSOS do contrato de dispatch.
|
|
@@ -4,7 +4,7 @@ description: Conduz a AUTORIA de mídia gerada por IA — escolher o modelo pelo
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando a tarefa for PRODUZIR imagem ou vídeo por IA (catálogo, marketing, asset de LP) e alguém precisar decidir modelo, prompt e aprovação
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
stacks:
|
|
9
9
|
- dotnet
|
|
10
10
|
- nextjs
|
|
@@ -4,7 +4,7 @@ description: Leva uma feature do pedido ao plano aprovado — roteia o tipo de t
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando uma feature, bug ou chore começar ("/morph-plan {feature}", "vamos planejar X"), ou ao retomar uma feature cujo gate plan ainda não foi aprovado
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -95,11 +95,11 @@ O `create` já escreveu o esqueleto em `2-plan/plan.md` (leia e preencha; `chore
|
|
|
95
95
|
|
|
96
96
|
**Arquitetura**: componentes, fluxo de dados, edge cases **técnicos** e integrações; não repita os cenários.
|
|
97
97
|
|
|
98
|
-
**Reuso**: tabela `| conceito | veredito | alvo | why |`, veredito `REUSAR` | `ESTENDER` | `CRIAR`. **`CRIAR` exige `why`** — a consulta que respondeu "não existe" (`graph explain X → not-found; grep -rn X → 0`). Conceito de duas features vai para um módulo comum, nunca import cruzado entre slices. O validador `reuse` do `verify` cobra: símbolo novo homônimo de um existente reprova na mesma feature e avisa entre features; `CRIAR` declarado rebaixa a aviso. Conceito sem fatia que o escreva: falta fatia ou o conceito não é desta feature — resolva antes do gate.
|
|
98
|
+
**Reuso**: tabela `| conceito | veredito | alvo | why |`, veredito `REUSAR` | `ESTENDER` | `CRIAR`. **`CRIAR` exige `why`** — a consulta que respondeu "não existe" (`graph explain X → not-found; grep -rn X → 0`). Abstração nova (interface, base, factory, camada) soma ao `why` o segundo uso ou a próxima adição que ela barateia; sem isso é excesso (`architecture-engineering-lens#excess`). Conceito de duas features vai para um módulo comum, nunca import cruzado entre slices. O validador `reuse` do `verify` cobra: símbolo novo homônimo de um existente reprova na mesma feature e avisa entre features; `CRIAR` declarado rebaixa a aviso. Conceito sem fatia que o escreva: falta fatia ou o conceito não é desta feature — resolva antes do gate.
|
|
99
99
|
|
|
100
100
|
**Fatias** (`### Fn — título`): a unidade de entrega e de relatório (`3-implement/reports/Fn.md`).
|
|
101
101
|
- `persona:` obrigatório — o id sem `morph-`, cujo `domains` cobre a fatia (uma leitura de `agents.json`). Fatia que cria ou altera UI é `ui-designer`, mesmo sem o ramo de design; com `superfície:`, os standards são os daquela chave de `surfaces`.
|
|
102
|
-
- `standards:` — `morph-spec standards --find "<domínio>"` por domínio (o digest decide): os da persona mais o que a fatia exige, sempre `architecture-code-comments` e o de teste do stack; agente MAF soma `--category ai-agents`.
|
|
102
|
+
- `standards:` — `morph-spec standards --find "<domínio>"` por domínio (o digest decide): os da persona mais o que a fatia exige, sempre `architecture-code-comments`, `architecture-engineering-lens` e o de teste do stack; agente MAF soma `--category ai-agents`.
|
|
103
103
|
- `arquivos:` — os paths planejados, testes incluídos, **no máximo 8**: acima disso o sub-agente bate no teto de turnos.
|
|
104
104
|
- `depende:` opcional; `cobre:` lista os Cn — todo cenário é coberto por alguma fatia. Fatias sem `depende:` comum e sem arquivo em comum rodam em paralelo; o `plan-check` imprime as ondas.
|
|
105
105
|
- Cenário que se observa por um artefato de outra fatia (rota, endpoint, componente que ela cria) faz da fatia que o cobre um `depende:` daquela — senão as duas caem na mesma onda e o teste do cenário não tem por onde provar. O `plan-check` não vê de quem é a rota: a regra é sua.
|
|
@@ -4,7 +4,7 @@ description: Conduz o Gate 3 — despacha verificador ∥ revisor (∥ seguranç
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando a fase review começar, com todas as fatias com relatório final e o verify da feature verde
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-review
|
|
@@ -4,7 +4,7 @@ description: Localiza um standard específico via busca server-side (morph-spec
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando precisar consultar um standard específico durante a implementação
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-standards
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase opcional de UI/UX de uma feature com plano aprovado
|
|
|
4
4
|
version: core
|
|
5
5
|
when_to_use: Use quando o ramo de design for tomado (morph-spec advance {feature} --design, depois do gate do plano) e antes de /morph-apply
|
|
6
6
|
user-invocable: true
|
|
7
|
-
cliVersion: "9.
|
|
7
|
+
cliVersion: "9.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-uiux
|
|
@@ -496,7 +496,7 @@
|
|
|
496
496
|
"example": "#exemplo-c-completo",
|
|
497
497
|
"content-types": "#datacontent-vs-uricontent"
|
|
498
498
|
},
|
|
499
|
-
"digest": "Vision em MAF usa ChatMessage multimodal (Microsoft.Extensions.AI): new ChatMessage(ChatRole.User, [new TextContent(pergunta), imagem]) passado a agent.RunAsync. Imagem em URL pública: UriContent(uri, mediaType); arquivo local: DataContent.LoadFromAsync(path), o helper canônico e preferido; bytes já em memória: new DataContent(BinaryData, mediaType). Upload de usuário ou imagem privada usa DataContent, nunca URL temporária (pode expirar); CDN estável usa UriContent. O modelo vem do alias vision no Model Registry, pois nem todo provider suporta visão. Dado tipado: RunAsync<T> com
|
|
499
|
+
"digest": "Vision em MAF usa ChatMessage multimodal (Microsoft.Extensions.AI): new ChatMessage(ChatRole.User, [new TextContent(pergunta), imagem]) passado a agent.RunAsync. Imagem em URL pública: UriContent(uri, mediaType); arquivo local: DataContent.LoadFromAsync(path), o helper canônico e preferido; bytes já em memória: new DataContent(BinaryData, mediaType). Upload de usuário ou imagem privada usa DataContent, nunca URL temporária (pode expirar); CDN estável usa UriContent. O modelo vem do alias vision no Model Registry, pois nem todo provider suporta visão. Dado tipado: RunAsync<T> com record, nunca regex em response.Text. Proibido: base64 manual, imagem 4K sem resize (tokens cobrados por resolução; ex.: 800px para OCR), vision quando já há texto extraído ou um parser/OCR determinístico basta. PDF: confirme application/pdf no provider."
|
|
500
500
|
},
|
|
501
501
|
{
|
|
502
502
|
"id": "ai-agents-multi-agent-patterns",
|
|
@@ -692,7 +692,7 @@
|
|
|
692
692
|
"type": "#definindo-o-tipo-de-saída",
|
|
693
693
|
"validation": "#validação-pós-call"
|
|
694
694
|
},
|
|
695
|
-
"digest": "Every agent whose output feeds another system returns a typed record, never free text. Form 1 is RunAsync<T>; Form 2 is ResponseFormat = ChatResponseFormat.ForJsonSchema<T>() in ChatOptions. Type is a
|
|
695
|
+
"digest": "Every agent whose output feeds another system returns a typed record, never free text. Form 1 is RunAsync<T>; Form 2 is ResponseFormat = ChatResponseFormat.ForJsonSchema<T>() in ChatOptions. Type is a record with [Description] on the type and [JsonPropertyName] on every property. Documented limits: ResponseFormat does not accept a primitive or an array at the root (use a wrapper), and in streaming you must build the whole response with ToAgentResponseAsync() before deserialising. Schema validates shape, not semantics — always validate business rules after the call. Do not use temperature as the example of a normal ChatOption."
|
|
696
696
|
},
|
|
697
697
|
{
|
|
698
698
|
"id": "ai-agents-sweet-spot",
|
|
@@ -801,7 +801,7 @@
|
|
|
801
801
|
"rules": "#padrões-obrigatórios",
|
|
802
802
|
"cqrs": "#anti-patterns-nunca-fazer-em-vsa"
|
|
803
803
|
},
|
|
804
|
-
"digest": "Uma slice por operação em Features/{Entity}Feature/{Verb}{Entity}/: Request e Response (
|
|
804
|
+
"digest": "Uma slice por operação em Features/{Entity}Feature/{Verb}{Entity}/: Request e Response (records) no mesmo arquivo do Handler, Validator FluentValidation (nenhum em GetAll) e Endpoint `IApiEndpoint` `internal`. O handler implementa o `IHandler<TRequest, TResponse>` próprio, devolve `Result<T>` (erros em `{Entity}Errors`, 1 por feature), injeta `ApplicationDbContext` direto e chama `SaveChangesAsync` nas escritas; o endpoint usa `result.Match()`: o sucesso recebe o valor no lambda (nunca `result.Value`) e a falha vira `error.ToHttpResult()` (status pelo `ErrorType`, ProblemDetails), nunca `Results.BadRequest` para todo erro, declarando cada status com `.ProducesProblem`. Decorators Scrutor: Logging -> Validation -> Handler. PROIBIDO: MediatR/IRequest, AggregateRoot, DomainEvent, CQRS formal, Application Service layer, DTOs compartilhados entre features e `IRepository<T>`/`IUnitOfWork` (DbSet já é repository, vira código morto); store dedicado só com justificativa em `plan.md` (`## Decisões`). Não misture VSA com DDD."
|
|
805
805
|
},
|
|
806
806
|
{
|
|
807
807
|
"id": "backend-api-validation",
|
|
@@ -821,7 +821,7 @@
|
|
|
821
821
|
"rules": "#validation-patterns",
|
|
822
822
|
"state": "#state-checks-in-the-handler"
|
|
823
823
|
},
|
|
824
|
-
"digest": "Request/DTO validation in the VSA slice: one
|
|
824
|
+
"digest": "Request/DTO validation in the VSA slice: one `AbstractValidator<TRequest>` (FluentValidation) next to the handler, checking SHAPE only (required, length, range, format, child items via RuleForEach/ChildRules; no DbContext; time rules read an injected TimeProvider inside the rule). The ValidationDecorator runs it before the handler and short-circuits with `Result.Failure(new ValidationError([...]))`; the endpoint maps it with `error.ToHttpResult()` to 400 ProblemDetails with `errors[]` (decorator and conversion in fluent-validation-vsa.md, ValidationError/ErrorHttpMapping in result-pattern.md). Never throw (ValidationException/InvalidOperationException), never validate in the endpoint lambda, never mix DataAnnotations with FluentValidation (minimal APIs have no ModelState). Existence/uniqueness/state checks live in the handler and return typed `{Entity}Errors` (NotFound 404, Conflict 409, Failure 400), never `Result.Failure(\"string\")`. State checks validate what is INVALID, not what is valid, so a new flow (e.g. a free flow that skips PendingPayment) does not break: ordered status enum (Created=0 ... EmailSent=4) with error states at 100+ (Failed=100, Cancelled=101, Refunded=102), blocked by `status >= Completed`, an error-state list, or `status >= Failed`. FORBIDDEN: `if (status != Expected)`, exhaustive switches over valid states, business rules mixed into the state check (keep `RequiresPayment && !IsPaid` separate). Document all flows in plan.md (## Decisões) and test each."
|
|
825
825
|
},
|
|
826
826
|
{
|
|
827
827
|
"id": "backend-database-postgresql-database",
|
|
@@ -883,7 +883,7 @@
|
|
|
883
883
|
"decorator": "#validationdecorator-pattern",
|
|
884
884
|
"conversion": "#fluentvalidation-to-validationerror-conversion"
|
|
885
885
|
},
|
|
886
|
-
"digest": "One
|
|
886
|
+
"digest": "One `AbstractValidator<TRequest>` per request DTO (FluentValidation 12), in the same feature folder as the handler; no `RuleSet` grouping and no `IValidateOptions<T>`. Never validate request shape inside the handler or endpoint (existence/state checks do belong in the handler): `ValidationDecorator<TRequest, TResponse>` wraps every `IHandler` via Scrutor, collects all `IValidator<TRequest>`, runs them in parallel (`Task.WhenAll`) and on failure short-circuits to `Result.Failure(ValidationError)` (an array of `Error.Validation(code, message)`), supporting both `Result` and `Result<T>`. Never throw `ValidationException`. In Program.cs call `AddValidatorsFromAssembly()` BEFORE `AddHandlersFromAssembly()` so the decorator can resolve validators. Always give user-facing `.WithMessage()` text. Inject `TimeProvider` instead of reading `DateTime.UtcNow` and read it INSIDE the rule (`LessThanOrEqualTo(_ => timeProvider.GetUtcNow().Year)`), so the year is evaluated per validation (a value captured in the constructor goes stale in a singleton/cached validator; AddValidatorsFromAssembly defaults to Scoped) and stays testable with `FakeTimeProvider`."
|
|
887
887
|
},
|
|
888
888
|
{
|
|
889
889
|
"id": "backend-dotnet-result-pattern",
|
|
@@ -988,7 +988,7 @@
|
|
|
988
988
|
"endpoint": "#complete-endpoint-example",
|
|
989
989
|
"registration": "#programcs-di-registration-order"
|
|
990
990
|
},
|
|
991
|
-
"digest": "Each VSA feature is a slice in `Features/{Feature}/{UseCase}/` with 5 files: Request, Response (
|
|
991
|
+
"digest": "Each VSA feature is a slice in `Features/{Feature}/{UseCase}/` with 5 files: Request, Response (records, may be inline), Handler, Validator, Endpoint; feature errors in `{Feature}Errors.cs` (`Error.NotFound/Conflict/Failure`). Handlers implement `IHandler<TRequest, TResponse>` (resolved from DI; NOT MediatR, decorators via Scrutor), inject `ApplicationDbContext` directly (`DbSet<T>` is the repository, `DbContext` the unit of work: no service layer, no `IRepository<T>`/`IUnitOfWork`), return `Result<T>` instead of throwing for expected failures. Endpoints are `internal` `IApiEndpoint`, only map HTTP and call `Match()`: success lambda receives the value (never read `.Value`), failure is `error.ToHttpResult()` (status by `ErrorType`, never `Results.BadRequest` for every error), with `.ProducesProblem` per failure status. Raw SQL or a dedicated hand-written store (outbox, lease) only with a `plan.md` (`## Decisões`) justification."
|
|
992
992
|
},
|
|
993
993
|
{
|
|
994
994
|
"id": "backend-integrations-asaas-asaas-api",
|
|
@@ -1028,7 +1028,7 @@
|
|
|
1028
1028
|
"jobs": "#job-types",
|
|
1029
1029
|
"retry": "#retry--error-handling"
|
|
1030
1030
|
},
|
|
1031
|
-
"digest": "Hangfire 1.8.25 on .NET 10, only with a real reason (survive restarts, schedules, deferred retries) recorded in plan.md (## Decisões); work that fits in the request stays in the slice handler. Storage is Neon Postgres via Hangfire.PostgreSql 1.21.1 with `UsePostgreSqlStorage(o => o.UseNpgsqlConnection(cs))` (the string overloads are [Obsolete]) and `HangfireConnection` on the direct/unpooled endpoint (schema install at startup is a migration, which Neon routes to the direct string; EnableLongPolling uses LISTEN/NOTIFY, unsupported by Neon's PgBouncer transaction mode); reference Newtonsoft.Json 13.0.4 explicitly or restore fails with NU1903 (Hangfire.Core pulls 11.0.1). A job is a thin
|
|
1031
|
+
"digest": "Hangfire 1.8.25 on .NET 10, only with a real reason (survive restarts, schedules, deferred retries) recorded in plan.md (## Decisões); work that fits in the request stays in the slice handler. Storage is Neon Postgres via Hangfire.PostgreSql 1.21.1 with `UsePostgreSqlStorage(o => o.UseNpgsqlConnection(cs))` (the string overloads are [Obsolete]) and `HangfireConnection` on the direct/unpooled endpoint (schema install at startup is a migration, which Neon routes to the direct string; EnableLongPolling uses LISTEN/NOTIFY, unsupported by Neon's PgBouncer transaction mode); reference Newtonsoft.Json 13.0.4 explicitly or restore fails with NU1903 (Hangfire.Core pulls 11.0.1). A job is a thin class in the slice that calls the slice handler (`IHandler<TRequest, Result>`); no XService layer. Hangfire.AspNetCore's AspNetCoreJobActivator opens a DI scope per job, so inject the ApplicationDbContext/handler directly (IDbContextFactory only for parallel work inside one job); never capture request-scoped services into Enqueue. Jobs are idempotent (check state, return). Expected failures come back as Result and the job logs and completes; unexpected ones are the exceptions EF/HttpClient already throw, uncaught, which `[AutomaticRetry(Attempts = 3, DelaysInSeconds = [60, 300, 900])]` retries; no try/catch, no manual retry loops. API: `BackgroundJob.Enqueue<TJob>(j => j.RunAsync(id, CancellationToken.None))`, `Schedule`, `RecurringJob.AddOrUpdate` with a stable id and cron (UTC), `ContinueJobWith`. Dashboard: IDashboardAuthorizationFilter requiring authenticated Admin, dev bypass only via IHostEnvironment.IsDevelopment() (never Request.Host, which the client controls)."
|
|
1032
1032
|
},
|
|
1033
1033
|
{
|
|
1034
1034
|
"id": "backend-integrations-neon-auth-neon-auth",
|
|
@@ -1211,26 +1211,7 @@
|
|
|
1211
1211
|
"tokens": "#stagger--timing",
|
|
1212
1212
|
"principles": "#css-animation-patterns"
|
|
1213
1213
|
},
|
|
1214
|
-
"digest": "CSS animation library for design-system.css
|
|
1215
|
-
},
|
|
1216
|
-
{
|
|
1217
|
-
"id": "frontend-design-system-naming",
|
|
1218
|
-
"name": "naming",
|
|
1219
|
-
"path": "frontend/design-system/naming.md",
|
|
1220
|
-
"category": "frontend",
|
|
1221
|
-
"subcategory": "design-system",
|
|
1222
|
-
"tags": [
|
|
1223
|
-
"frontend",
|
|
1224
|
-
"design-system"
|
|
1225
|
-
],
|
|
1226
|
-
"stacks": [
|
|
1227
|
-
"*"
|
|
1228
|
-
],
|
|
1229
|
-
"anchors": {
|
|
1230
|
-
"blocks": "#bem-for-reusable-components",
|
|
1231
|
-
"tokens": "#css-variables-with-namespace"
|
|
1232
|
-
},
|
|
1233
|
-
"digest": "CSS naming rests on four principles: a page prefix prevents conflicts, BEM for components gives clear hierarchy, namespaced variables avoid library collisions, and state suffixes keep modifiers consistent. Page-specific elements take the page name as prefix (.home-hero, .checkout-form, .dashboard-stats, .auth-form); reusable components use BEM: block .card, element .card__header, modifier .card--featured. Rule: BEM for reusable components, page prefix for page-specific elements. Custom properties go in :root under the --app- namespace (--app-primary, --app-spacing-md, --app-font-heading). State modifiers use fixed suffixes: --active, --disabled, --loading, --error (.button, .button--active, .button--disabled)."
|
|
1214
|
+
"digest": "CSS animation library for design-system.css (keyframes and the `.animate-*`/`.stagger-*` utility classes live in the file, not in a rule). For staggered lists set `animation-delay` AND `animation-fill-mode: backwards` (marked CRITICAL: otherwise elements flash before the delay). Always include the `@media (prefers-reduced-motion: reduce)` block (0.01ms durations, one iteration). Beyond CSS: Motion (formerly Framer Motion) for simple enter/exit, layout and gesture transitions (`frontend/nextjs/motion-patterns.md`); GSAP for ScrollTrigger, SVG morph, timelines (`frontend/gsap/gsap-core.md`)."
|
|
1234
1215
|
},
|
|
1235
1216
|
{
|
|
1236
1217
|
"id": "frontend-design-system-premium-finish",
|
|
@@ -1341,7 +1322,7 @@
|
|
|
1341
1322
|
"layout": "#root-layout--required-providers",
|
|
1342
1323
|
"routing": "#app-directory-structure"
|
|
1343
1324
|
},
|
|
1344
|
-
"digest": "Next.js 15 App Router, TypeScript only (no .js/.jsx). Server Components by default; add `'use client'` only for interaction (onClick, useState/useEffect/useRef), browser APIs, TanStack Query hooks and interactive shadcn/ui. `app/` is for routing only: business logic goes to `features/`, never in `page.tsx`. Never fetch data in a Client Component when a Server Component can
|
|
1325
|
+
"digest": "Next.js 15 App Router, TypeScript only (no .js/.jsx). Server Components by default; add `'use client'` only for interaction (onClick, useState/useEffect/useRef), browser APIs, TanStack Query hooks and interactive shadcn/ui. `app/` is for routing only: business logic goes to `features/`, never in `page.tsx`. Never fetch data in a Client Component when a Server Component can,. Co-locate `loading.tsx` and `error.tsx` beside `page.tsx`. Server Components call the .NET backend directly using the dedicated `BACKEND_API_PREFIX` from `@/lib/api/prefixes`, never the same-origin proxy prefix used by Client Components; always check `res.ok`. Avoid `route.ts` API routes (use the .NET API). The root `layout.tsx` wraps children in `QueryProvider` and the sonner `Toaster`. Fetch in `useEffect` and `'use client'` in the root layout are lint errors (frontend-nextjs-lint)."
|
|
1345
1326
|
},
|
|
1346
1327
|
{
|
|
1347
1328
|
"id": "frontend-nextjs-components",
|
|
@@ -1360,7 +1341,7 @@
|
|
|
1360
1341
|
"patterns": "#three-tier-hierarchy",
|
|
1361
1342
|
"shadcn": "#tier-1--shadcnui-primitives"
|
|
1362
1343
|
},
|
|
1363
|
-
"digest": "Three tiers (Next.js 16 + shadcn 4 CLI): `components/ui/` is shadcn CLI output (add via `npx shadcn@latest add`, NEVER edit because the CLI regenerates it; wrap it in `components/` instead); `components/` holds shared composed components with no business logic
|
|
1344
|
+
"digest": "Three tiers (Next.js 16 + shadcn 4 CLI): `components/ui/` is shadcn CLI output (add via `npx shadcn@latest add`, NEVER edit because the CLI regenerates it; wrap it in `components/` instead); `components/` holds shared composed components with no business logic (importing `features/` is a lint error, frontend-nextjs-lint); `features/*/components/` is feature-scoped and may know the domain. Add `'use client'` only if the component uses hooks, events or browser APIs (not on every component: unnecessary client JS). Never pass raw API/fetch data as props: the feature maps it to typed props. The shared data table is specified once in `admin-app/data-table.md`: do not write a second `components/data-table.tsx`; a feature list is a Tier 3 component that owns the columns and the URL-to-table mapping."
|
|
1364
1345
|
},
|
|
1365
1346
|
{
|
|
1366
1347
|
"id": "frontend-nextjs-data-fetching",
|
|
@@ -1379,7 +1360,7 @@
|
|
|
1379
1360
|
"server": "#server-component--tanstack-query-handoff",
|
|
1380
1361
|
"client": "#usequery-hook-pattern"
|
|
1381
1362
|
},
|
|
1382
|
-
"digest": "Server Components do the initial load and call the .NET backend directly with BACKEND_API_PREFIX; Client Components never call the backend — they hit a same-origin proxy route with PROXY_API_PREFIX. Two named constants, never one shared API_PREFIX: the side that drifts breaks silently at runtime. Client data is TanStack Query 5: useQuery for reads, useMutation for writes, then invalidateQueries({ queryKey: userKeys.lists() }) (object syntax). Keys come from a per-feature key factory, never hardcoded ['users']. Every response is parsed with a Zod schema. QueryClient
|
|
1363
|
+
"digest": "Server Components do the initial load and call the .NET backend directly with BACKEND_API_PREFIX; Client Components never call the backend — they hit a same-origin proxy route with PROXY_API_PREFIX. Two named constants, never one shared API_PREFIX: the side that drifts breaks silently at runtime. Client data is TanStack Query 5: useQuery for reads, useMutation for writes, then invalidateQueries({ queryKey: userKeys.lists() }) (object syntax). Keys come from a per-feature key factory, never hardcoded ['users']. Every response is parsed with a Zod schema. QueryClient is created once in useState; the Server Component passes initialData to the client hook. FORBIDDEN: fetching a whole collection to page/sort/filter in the browser — page on the server, query in the URL. Fetch in useEffect and a DB driver in Next are lint errors (frontend-nextjs-lint)."
|
|
1383
1364
|
},
|
|
1384
1365
|
{
|
|
1385
1366
|
"id": "frontend-nextjs-forms",
|
|
@@ -1420,7 +1401,7 @@
|
|
|
1420
1401
|
"scroll": "#section-3-scroll-animations",
|
|
1421
1402
|
"accessibility": "#section-7-wcag-accessibility-mandatory"
|
|
1422
1403
|
},
|
|
1423
|
-
"digest": "Component-level motion with Motion for React (the stack table's 'Framer Motion', its former name; motion 12+, current npm major 14): npm install motion and import from 'motion/react'. framer-motion is not deprecated (motion depends on it and re-exports it), but a codebase keeps one import path, motion/react
|
|
1404
|
+
"digest": "Component-level motion with Motion for React (the stack table's 'Framer Motion', its former name; motion 12+, current npm major 14): npm install motion and import from 'motion/react'. framer-motion is not deprecated (motion depends on it and re-exports it), but a codebase keeps one import path, motion/react (a framer-motion import is a lint error, frontend-nextjs-lint). Variants live in motion/variants.ts (fadeIn, slideInUp/Down/Left/Right, scaleIn, staggerContainer, staggerItem, pageTransition) and take durations and easings from @/lib/design-tokens (fast 0.15, base 0.3); never hardcode duration numbers or easing arrays. Scroll reveals: whileInView with viewport once: true for simple cases, useInView for control. Page transitions: AnimatePresence mode='wait' keyed by usePathname(), inside a 'use client' PageTransition provider -- the root app/layout.tsx stays a Server Component (no 'use client', keeps metadata) and just renders the provider. WCAG is mandatory: useReducedMotion() strips x/y/scale and keeps opacity, plus a prefers-reduced-motion CSS fallback. Scroll-driven scenes (ScrollTrigger, Lenis) belong to GSAP; never share an element with it."
|
|
1424
1405
|
},
|
|
1425
1406
|
{
|
|
1426
1407
|
"id": "frontend-nextjs-naming-conventions",
|
|
@@ -1439,7 +1420,7 @@
|
|
|
1439
1420
|
"files": "#complete-reference-table",
|
|
1440
1421
|
"components": "#complete-reference-table"
|
|
1441
1422
|
},
|
|
1442
|
-
"digest": "Next.js naming (prevents Linux case-sensitivity bugs). File names are ALWAYS kebab-case (`user-card.tsx`, never `UserCard.tsx`);
|
|
1423
|
+
"digest": "Next.js naming (prevents Linux case-sensitivity bugs). File names are ALWAYS kebab-case (`user-card.tsx`, never `UserCard.tsx`); components export PascalCase (`UserCard`); hook files are kebab-case too (`use-users.ts` -> `useUsers`, `use-user.ts` for a single GET, `use-create-user.ts`, `use-update-user.ts`, `use-delete-user.ts`). Zod schema files end in `.schemas.ts` (`createUserSchema`) and type files in `.types.ts`, with types derived via `z.infer` instead of hand-written duplicates. A feature `index.ts` re-exports. Named exports and the hook `use` prefix are lint errors, not prose (frontend-nextjs-lint). Never mix cases within a category (no `UserCard.tsx` next to `user-profile.tsx`)."
|
|
1443
1424
|
},
|
|
1444
1425
|
{
|
|
1445
1426
|
"id": "frontend-nextjs-nextjs-patterns",
|
|
@@ -1458,7 +1439,7 @@
|
|
|
1458
1439
|
"auth": "#route-handlers-bff-pattern",
|
|
1459
1440
|
"caching": "#react-query--neon"
|
|
1460
1441
|
},
|
|
1461
|
-
"digest": "Next.js 15 App Router (not Pages Router): Server Components by default, `'use client'` only for state, effects, events or browser APIs; colocate `loading.tsx` and `error.tsx`
|
|
1442
|
+
"digest": "Next.js 15 App Router (not Pages Router): Server Components by default, `'use client'` only for state, effects, events or browser APIs; colocate `loading.tsx` and `error.tsx` with `page.tsx`. Route Handlers act as a BFF: check `auth.getSession()` (401 if absent) and delegate to the .NET API; database access lives in the .NET backend via EF Core (a DB driver in Next is a lint error, frontend-nextjs-lint). Validate input with Zod on client and server (`safeParse`, 400). Fetch with TanStack Query (`useQuery`/`useMutation`, `invalidateQueries` on success). Forms: react-hook-form + `zodResolver`. shadcn is copied via `npx shadcn@latest add`, not an npm dependency. Keep `\"strict\": true` plus `noUncheckedIndexedAccess` (agents self-correct from compiler errors); API responses are a Zod schema + `z.infer`."
|
|
1462
1443
|
},
|
|
1463
1444
|
{
|
|
1464
1445
|
"id": "frontend-nextjs-project-structure",
|
|
@@ -1477,7 +1458,7 @@
|
|
|
1477
1458
|
"structure": "#canonical-folder-tree",
|
|
1478
1459
|
"organization": "#feature-index-pattern"
|
|
1479
1460
|
},
|
|
1480
|
-
"digest": "Next.js 15 App Router, src/ layout with the @/ alias, feature-based. src/app/ is routing only (layout, page, loading, error)
|
|
1461
|
+
"digest": "Next.js 15 App Router, src/ layout with the @/ alias, feature-based. src/app/ is routing only (layout, page, loading, error); screen logic lives in features/. Each src/features/{feature-name}/ holds components/, hooks/ (TanStack Query hooks such as use-users.ts, use-create-user.ts), types/ (*.types.ts plus *.schemas.ts with Zod and z.infer) and an index.ts that is the explicit public API. NEVER import one feature from another (extract to components/ or lib/); components/ is presentation only with NO business logic, and components/ui/ is shadcn, never edited directly. Deep imports from outside a feature, components/ -> features/, features/ -> app/ and shared hooks/ -> the API client are lint errors (frontend-nextjs-lint). lib/ holds api-client.ts (typed fetch wrapper for the .NET API) and query-client.tsx; types/api.ts has PaginatedResponse<T> and ApiError; env.mjs validates env vars with Zod."
|
|
1481
1462
|
},
|
|
1482
1463
|
{
|
|
1483
1464
|
"id": "frontend-nextjs-state-management",
|
|
@@ -1496,7 +1477,7 @@
|
|
|
1496
1477
|
"patterns": "#state-decision-tree",
|
|
1497
1478
|
"server": "#server-state-tanstack-query"
|
|
1498
1479
|
},
|
|
1499
|
-
"digest": "Server state (anything from the .NET API) lives in TanStack Query, never copied into `useState` via `useEffect`; derive state from server data instead of syncing it. Local UI state (modal open, form step, selected id) uses `useState`. A list's page, sort and filters, and a page's active tab, go in the URL (`searchParams`), never `useState`, so a refresh or shared link reopens the same view. Do not use React Context for server state (no caching or dedup); Context is for truly global theme, auth user or locale
|
|
1480
|
+
"digest": "Server state (anything from the .NET API) lives in TanStack Query, never copied into `useState` via `useEffect`; derive state from server data instead of syncing it. Local UI state (modal open, form step, selected id) uses `useState`. A list's page, sort and filters, and a page's active tab, go in the URL (`searchParams`), never `useState`, so a refresh or shared link reopens the same view. Do not use React Context for server state (no caching or dedup); Context is for truly global theme, auth user or locale. Zustand/Redux imports are lint errors (frontend-nextjs-lint); the one exception is an eslint-disable-next-line with the reason in a single store file, only if ALL hold: state needed in 5+ unrelated components, complex update logic, Context causes measurable re-render problems, and the state is not from the server."
|
|
1500
1481
|
},
|
|
1501
1482
|
{
|
|
1502
1483
|
"id": "frontend-nextjs-testing",
|
|
@@ -1830,7 +1811,7 @@
|
|
|
1830
1811
|
"not-worth": "#o-que-não-merece",
|
|
1831
1812
|
"size": "#tamanho"
|
|
1832
1813
|
},
|
|
1833
|
-
"digest": "Default is NO comment: code explains itself through names, types and tests. Before commenting, rename, extract a function or named constant, encode the state in the type, or write a test; comment only what none of these can express: an invariant the type does not express, an order that matters, an external quirk (third-party API, library bug with its link), or the contract of a package published for consumers outside the repo. Never process history (task, UC, ADR, FR, Gate, evaluator, spec.md, mockup: commit message and plan.md (## Decisões); in a test the link to the postcondition goes in the test NAME), never restate the code, no XML doc/JSDoc on application members that repeats the signature, no file headers, section banners, #region, commented-out code or loose TODOs, no claims about behavior (make them test assertions). One line is normal, ~3 is the ceiling; more than one comment line per ten code lines means the names are not doing the work. A heavily commented neighbour file is not a model. The comment-guard hook blocks an edit that ADDS process history, a banner/#region, a block over 3 lines or a doc-comment outside a published package; the verify validators node (code-budget) warns on added comments that cite process and on added comment density."
|
|
1814
|
+
"digest": "Default is NO comment: code explains itself through names, types and tests. Before commenting, rename, extract a function or named constant, encode the state in the type, or write a test; comment only what none of these can express: an invariant the type does not express, an order that matters, an external quirk (third-party API, library bug with its link), or the contract of a package published for consumers outside the repo. Never process history (task, UC, ADR, FR, Gate, evaluator, spec.md, mockup: commit message and plan.md (## Decisões); in a test the link to the postcondition goes in the test NAME), never restate the code, no XML doc/JSDoc on application members that repeats the signature, no file headers, section banners, #region, commented-out code or loose TODOs, no claims about behavior (make them test assertions). One line is normal, ~3 is the ceiling; more than one comment line per ten code lines means the names are not doing the work. A heavily commented neighbour file is not a model. The comment-guard hook blocks an edit that ADDS process history, a banner/#region, commented-out code, a block over 3 lines or a doc-comment outside a published package; the verify validators node (code-budget) warns on added comments that cite process and on added comment density."
|
|
1834
1815
|
},
|
|
1835
1816
|
{
|
|
1836
1817
|
"id": "ai-agents-tool-adapters",
|
|
@@ -1857,7 +1838,7 @@
|
|
|
1857
1838
|
"reais": "#exemplos-reais",
|
|
1858
1839
|
"regras": "#regras"
|
|
1859
1840
|
},
|
|
1860
|
-
"digest": "A tool that carries business rule keeps apart three things that change for different reasons: the RULE (
|
|
1841
|
+
"digest": "A tool that carries business rule keeps apart three things that change for different reasons: the RULE (class XOps(...), explicit AddScoped; never *Service, which MORPH.md bans as a layer between handler and data), the sentence the MODEL reads, and the EFFECT a human sees. Each Ops method returns a typed outcome (abstract record XDesfecho, one record per case); the model-facing text (description, refusal, self-correction, success, the ToolUnavailable decision) lives in the adapter, in public static object Render(XDesfecho), while human text delivered by code (task body, note, ack) stays in Ops because it is an effect. Checkable by grep: Ops names no tool and instructs no model. The adapter (AIFunctionFactory.Create) only builds the typed request, calls Ops and returns Render: zero rule, not a line count, and a long dynamic description stays byte for byte. Two test layers: Ops tests assert outcome, calls and order on the fake, never text; contract tests assert Render's exact literal and .Description, with a golden of name, description and schema per real tenant. A neutral refactor is proven before any test moves: a proof commit with the old suite untouched and green (offline evals included), then the migration, with mutation run only against the new tests. \"Already covered\" needs proof assertion by assertion (11 of 22 such claims had lost one); the tests left at the origin must be identical to the base; mutation on the new tests found rules the old suite never protected. The C# blocks were compiled against the pin and the three xunit tests run."
|
|
1861
1842
|
},
|
|
1862
1843
|
{
|
|
1863
1844
|
"id": "frontend-design-system-art-direction",
|
|
@@ -1879,6 +1860,75 @@
|
|
|
1879
1860
|
"prototype": "#section-7-prototype-and-self-review"
|
|
1880
1861
|
},
|
|
1881
1862
|
"digest": "Order beats talent: before any component of a new or changed screen, write 1-design/direcao.md with the concept in one sentence, the visual metaphor, what makes it memorable, and what it must NOT look like. New screens and brand moments (login, onboarding, first screen, empty state, success) explore 2-3 DISTINCT directions and recommend one with a product reason. Avoid template tells (raw shadcn look, white card centered on gray, generic icon list, default fonts, flat backgrounds, mobile as stacked desktop, decorative fade-ins, made-up numbers); three or more means raise it. Mobile is composed at 390px on its own (bottom sheet, thumb zone, 44px targets). Motion tells something with the lightest tool (CSS keyframes > scroll-driven CSS > Framer Motion > GSAP), transform/opacity only, and a composed reduced-motion version. Prove it in 1-design/prototipos/{screen}.html with the project REAL tokens, screenshotted at 1280 and 390 and revised until it passes."
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
"id": "architecture-engineering-lens",
|
|
1866
|
+
"name": "engineering lens",
|
|
1867
|
+
"path": "architecture/engineering-lens.md",
|
|
1868
|
+
"category": "architecture",
|
|
1869
|
+
"subcategory": null,
|
|
1870
|
+
"tags": [
|
|
1871
|
+
"architecture",
|
|
1872
|
+
"clean-code",
|
|
1873
|
+
"review"
|
|
1874
|
+
],
|
|
1875
|
+
"stacks": [
|
|
1876
|
+
"*"
|
|
1877
|
+
],
|
|
1878
|
+
"anchors": {
|
|
1879
|
+
"fragility": "#fragilidade",
|
|
1880
|
+
"dead-code": "#código-morto",
|
|
1881
|
+
"excess": "#excesso",
|
|
1882
|
+
"readability": "#legibilidade",
|
|
1883
|
+
"extensibility": "#extensibilidade",
|
|
1884
|
+
"ai-vs-code": "#ia-e-código",
|
|
1885
|
+
"git": "#git",
|
|
1886
|
+
"review-blockers": "#o-que-bloqueia-no-gate-3"
|
|
1887
|
+
},
|
|
1888
|
+
"digest": "Write for whoever inherits the repo tomorrow: the project convention beats taste, the simplest thing that works beats the general one, fix the root cause. Fragility: no swallowed catch, handle null/absence from boundaries (HTTP, DB, file, LLM), no hidden order dependency, no strict parser on real data, no blind guard, no test that passes without proving the rule. Dead code: a symbol, endpoint, flag, config or table without a real consumer goes, and so does commented-out code; two paths doing the same thing become one. Excess: no abstraction without a second use today, no pass-through layer, no speculative config, no reinvented stdlib; a plan CREATE of an abstraction names the second use or the next addition it makes cheaper. Readability: descriptive searchable domain names, nouns for classes and verbs for methods, small single-purpose functions, at most 3 parameters, no boolean flag that forks the method (two methods), no hidden side effect, positive conditionals, repeated literals become constants. Extensibility: the next likely addition touches few files and no scattered switch. AI: an unbreakable rule stays in code (ai-agents-guardrails); hand-written NL classification may become structured output only when measured by eval. Git: branch morph/{f}; Conventional Commits <type>(<scope>): <subject>, enforced by the conventional-commit hook. Gate 3 blocks only what the DIFF introduced: swallowed exception, boolean flag parameter, hidden side effect, symbol/flag/config without consumer or commented-out code, abstraction without second use nor plan why, repeated magic literal in a comparison; everything else is a note."
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
"id": "backend-dotnet-analyzers",
|
|
1892
|
+
"name": "analyzers",
|
|
1893
|
+
"path": "backend/dotnet/analyzers.md",
|
|
1894
|
+
"category": "backend",
|
|
1895
|
+
"subcategory": "dotnet",
|
|
1896
|
+
"tags": [
|
|
1897
|
+
"backend",
|
|
1898
|
+
"dotnet",
|
|
1899
|
+
"analyzers"
|
|
1900
|
+
],
|
|
1901
|
+
"stacks": [
|
|
1902
|
+
"dotnet"
|
|
1903
|
+
],
|
|
1904
|
+
"anchors": {
|
|
1905
|
+
"files": "#arquivos",
|
|
1906
|
+
"rules": "#o-que-cada-regra-compra",
|
|
1907
|
+
"not-a-rule": "#o-que-não-é-regra"
|
|
1908
|
+
},
|
|
1909
|
+
"digest": "Rules with a reason that must never break are build errors, not prose: three files at the solution root, no .csproj change. Directory.Build.props adds Microsoft.CodeAnalysis.BannedApiAnalyzers 5.6.0 (PrivateAssets=all), BannedSymbols.txt as AdditionalFiles and morph.globalconfig as GlobalAnalyzerConfigFiles (with Central Package Management the version goes to Directory.Packages.props). BannedSymbols.txt bans M:System.Guid.NewGuid (use Guid.CreateVersion7(): time-ordered, does not fragment the Postgres PK index). morph.globalconfig sets RS0030 and CA2016 (a CancellationToken received and not forwarded) to error. A new banned API is one BannedSymbols.txt line with the reason after the semicolon, never a prose rule. sealed, primary constructors, var, expression bodies and using order are taste: neither prose nor analyzer; follow the neighbouring file."
|
|
1910
|
+
},
|
|
1911
|
+
{
|
|
1912
|
+
"id": "frontend-nextjs-lint",
|
|
1913
|
+
"name": "lint",
|
|
1914
|
+
"path": "frontend/nextjs/lint.md",
|
|
1915
|
+
"category": "frontend",
|
|
1916
|
+
"subcategory": "nextjs",
|
|
1917
|
+
"tags": [
|
|
1918
|
+
"frontend",
|
|
1919
|
+
"nextjs",
|
|
1920
|
+
"lint",
|
|
1921
|
+
"eslint"
|
|
1922
|
+
],
|
|
1923
|
+
"stacks": [
|
|
1924
|
+
"nextjs"
|
|
1925
|
+
],
|
|
1926
|
+
"anchors": {
|
|
1927
|
+
"files": "#arquivos",
|
|
1928
|
+
"rules": "#o-que-cada-regra-compra",
|
|
1929
|
+
"not-a-rule": "#o-que-não-é-regra"
|
|
1930
|
+
},
|
|
1931
|
+
"digest": "Rules with a reason that a machine can see are lint errors, not prose: one eslint.config.mjs at the Next app root, flat config spreading eslint-config-next/core-web-vitals and eslint-config-next/typescript, no new plugin. ESLint 9 (eslint-plugin-import/react peer range; the bundled typescript-eslint wants TypeScript <6.1); Next 16 next build no longer lints; the verify build node runs eslint --quiet on the files the feature changed (legacy lint debt never reddens a feature), from the app root, when eslint.config.* and eslint are present. no-restricted-imports bans framer-motion (one import path, motion/react), zustand/redux/@reduxjs/toolkit (server state is TanStack Query, page and filters in the URL), DB drivers pg/@neondatabase/serverless/@prisma/client/drizzle-orm/postgres (Next never touches the database; the .NET API does), the legacy shadcn @/components/ui/form, and @/features/*/* deep imports outside src/features (use the feature index.ts). import/no-restricted-paths: src/components never imports src/features, src/features never imports src/app, src/hooks never imports the API client (lib/api-client.ts, lib/api). no-restricted-syntax: fetch or apiClient called inside useEffect, and 'use client' in the root app/layout.tsx. import/no-default-export except Next convention files (page, layout, loading, error, not-found, template, default, route, sitemap, robots, icons, OG images) and *.config.*. @typescript-eslint/no-explicit-any error, no-console warn. A new restriction is one line in this file with the reason in its message; a one-off exception is eslint-disable-next-line with the reason. CSS class naming, animation class catalogs, optional className, Zod on props, motion counts and offsets, QueryClient defaults and prop-drilling depth are taste: neither prose nor lint."
|
|
1882
1932
|
}
|
|
1883
1933
|
]
|
|
1884
1934
|
}
|
|
@@ -819,17 +819,6 @@
|
|
|
819
819
|
"verifiedAgainst": "CSS animations/transitions (language-level, no framework).",
|
|
820
820
|
"provedBy": []
|
|
821
821
|
},
|
|
822
|
-
"frontend-design-system-naming": {
|
|
823
|
-
"aliases": [
|
|
824
|
-
"BEM",
|
|
825
|
-
"CSS naming",
|
|
826
|
-
"class naming",
|
|
827
|
-
"design token naming",
|
|
828
|
-
"component naming"
|
|
829
|
-
],
|
|
830
|
-
"verifiedAgainst": "CSS (BEM + custom properties — language-level, no framework).",
|
|
831
|
-
"provedBy": []
|
|
832
|
-
},
|
|
833
822
|
"frontend-design-system-premium-finish": {
|
|
834
823
|
"aliases": [
|
|
835
824
|
"premium finish",
|
|
@@ -1223,6 +1212,47 @@
|
|
|
1223
1212
|
],
|
|
1224
1213
|
"verifiedAgainst": "the `login-ciclo-do-produto` design round (2026-10-06): a correct, plain design was rejected; a second round with a written direction, an HTML prototype and a screenshot self-review was approved on first sight.",
|
|
1225
1214
|
"provedBy": []
|
|
1215
|
+
},
|
|
1216
|
+
"architecture-engineering-lens": {
|
|
1217
|
+
"aliases": [
|
|
1218
|
+
"clean code",
|
|
1219
|
+
"código limpo",
|
|
1220
|
+
"código morto",
|
|
1221
|
+
"dead code",
|
|
1222
|
+
"fragilidade",
|
|
1223
|
+
"excesso",
|
|
1224
|
+
"extensibilidade",
|
|
1225
|
+
"flag argument",
|
|
1226
|
+
"conventional commits"
|
|
1227
|
+
],
|
|
1228
|
+
"verifiedAgainst": "C#, TypeScript e JavaScript (convenção de linguagem, sem pacote externo); Conventional Commits 1.0.0.",
|
|
1229
|
+
"provedBy": []
|
|
1230
|
+
},
|
|
1231
|
+
"backend-dotnet-analyzers": {
|
|
1232
|
+
"aliases": [
|
|
1233
|
+
"analyzer",
|
|
1234
|
+
"roslyn analyzer",
|
|
1235
|
+
"banned api",
|
|
1236
|
+
"BannedSymbols",
|
|
1237
|
+
"Guid.NewGuid",
|
|
1238
|
+
"CreateVersion7",
|
|
1239
|
+
"CA2016"
|
|
1240
|
+
],
|
|
1241
|
+
"verifiedAgainst": ".NET SDK 10.0.402, Microsoft.CodeAnalysis.BannedApiAnalyzers 5.6.0 (sonda: `Guid.NewGuid()` → erro RS0030, token não repassado → erro CA2016, código conforme → 0 erros).",
|
|
1242
|
+
"provedBy": []
|
|
1243
|
+
},
|
|
1244
|
+
"frontend-nextjs-lint": {
|
|
1245
|
+
"aliases": [
|
|
1246
|
+
"eslint",
|
|
1247
|
+
"eslint.config.mjs",
|
|
1248
|
+
"lint rule",
|
|
1249
|
+
"no-restricted-imports",
|
|
1250
|
+
"no-restricted-paths",
|
|
1251
|
+
"eslint-config-next",
|
|
1252
|
+
"default export"
|
|
1253
|
+
],
|
|
1254
|
+
"verifiedAgainst": "eslint 9.39.5, eslint-config-next 16.4.2 (typescript-eslint 8.71.2, eslint-plugin-import 2.32.0), next 16.4.2, typescript 6.0.3 (sonda: um arquivo ruim por regra → erro da regra esperada, `no-console` → aviso, arquivos conformes e o scaffold `morph-spec scaffold nextjs` → 0 problemas).",
|
|
1255
|
+
"provedBy": []
|
|
1226
1256
|
}
|
|
1227
1257
|
},
|
|
1228
1258
|
"sharedAliases": {
|
|
@@ -1295,10 +1325,6 @@
|
|
|
1295
1325
|
"architecture-vertical-slice-vertical-slice",
|
|
1296
1326
|
"backend-dotnet-vsa-handler-patterns"
|
|
1297
1327
|
],
|
|
1298
|
-
"component naming": [
|
|
1299
|
-
"frontend-design-system-naming",
|
|
1300
|
-
"frontend-nextjs-naming-conventions"
|
|
1301
|
-
],
|
|
1302
1328
|
"video generation": [
|
|
1303
1329
|
"ai-agents-media-video",
|
|
1304
1330
|
"frontend-design-system-ai-video-generation"
|
|
@@ -93,7 +93,7 @@ await upsert({ key: doc.sourceId, hash: sha256(doc.body) });
|
|
|
93
93
|
## Na revisão
|
|
94
94
|
|
|
95
95
|
Na hora da edição, o hook `comment-guard` bloqueia o comentário **adicionado** que é história de
|
|
96
|
-
processo, banner/`#region`, bloco de mais de 3 linhas ou `///`/JSDoc em projeto que não é pacote
|
|
96
|
+
processo, banner/`#region`, código comentado, bloco de mais de 3 linhas ou `///`/JSDoc em projeto que não é pacote
|
|
97
97
|
publicado. Comentário que o arquivo já tinha nunca é acusado. Repetir o código em uma linha não é
|
|
98
98
|
detectável por forma: fica com a revisão abaixo.
|
|
99
99
|
|