create-sdd-ai-stack 0.1.17

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.
Files changed (72) hide show
  1. package/AGENTS.md +164 -0
  2. package/APP-STACK.md +31 -0
  3. package/APP.md +46 -0
  4. package/ARCHITECTURE.md +115 -0
  5. package/DESIGN.md +219 -0
  6. package/LICENSE +21 -0
  7. package/NEXT.md +345 -0
  8. package/NODE.md +107 -0
  9. package/REACT.md +92 -0
  10. package/README.md +260 -0
  11. package/SKILLS/check-docs/SKILL.md +24 -0
  12. package/SKILLS/check-docs/check-docs.mjs +56 -0
  13. package/SKILLS/create-feature/SKILL.md +40 -0
  14. package/SKILLS/create-feature/create-feature.mjs +128 -0
  15. package/SKILLS/create-feature.sh +112 -0
  16. package/SKILLS/install-submodule/SKILL.md +42 -0
  17. package/SKILLS/install-submodule/install-submodule.mjs +119 -0
  18. package/bin/create-sdd-ai-stack.mjs +93 -0
  19. package/docs/CHANGELOG.md +209 -0
  20. package/docs/PLANNING.md +68 -0
  21. package/docs/PRODUCT.md +76 -0
  22. package/docs/RELEASE.md +332 -0
  23. package/lib/check-links.mjs +42 -0
  24. package/lib/constants.mjs +60 -0
  25. package/lib/scaffold.mjs +253 -0
  26. package/package.json +80 -0
  27. package/specs/BACKLOG.md +24 -0
  28. package/specs/PLAN.md +57 -0
  29. package/specs/ROADMAP.md +35 -0
  30. package/specs/history/phases/phase-0-bootstrap.md +67 -0
  31. package/specs/tasks/TASK_TEMPLATE.md +46 -0
  32. package/src/cli.mjs +119 -0
  33. package/stacks/README.md +33 -0
  34. package/stacks/ai.md +52 -0
  35. package/stacks/ci.md +59 -0
  36. package/stacks/database.md +56 -0
  37. package/stacks/git.md +51 -0
  38. package/stacks/shadcn.md +52 -0
  39. package/stacks/tailwind.md +65 -0
  40. package/stacks/testing.md +74 -0
  41. package/stacks/typescript.md +58 -0
  42. package/template/next/.env.example +4 -0
  43. package/template/next/README.md +47 -0
  44. package/template/next/biome.json +36 -0
  45. package/template/next/gitignore +32 -0
  46. package/template/next/next.config.ts +12 -0
  47. package/template/next/package.json +47 -0
  48. package/template/next/playwright.config.ts +21 -0
  49. package/template/next/postcss.config.mjs +7 -0
  50. package/template/next/src/app/(app)/app/page.tsx +18 -0
  51. package/template/next/src/app/(app)/error.tsx +30 -0
  52. package/template/next/src/app/(app)/layout.tsx +25 -0
  53. package/template/next/src/app/(marketing)/page.tsx +73 -0
  54. package/template/next/src/app/globals.css +437 -0
  55. package/template/next/src/app/layout.tsx +41 -0
  56. package/template/next/src/app/not-found.tsx +11 -0
  57. package/template/next/src/features/example/actions.ts +43 -0
  58. package/template/next/src/features/example/application/create-example.usecase.ts +26 -0
  59. package/template/next/src/features/example/container.ts +16 -0
  60. package/template/next/src/features/example/domain/IExampleRepository.ts +11 -0
  61. package/template/next/src/features/example/domain/example.schema.ts +18 -0
  62. package/template/next/src/features/example/infrastructure/example.repository.ts +26 -0
  63. package/template/next/src/features/example/ui/create-example-form.tsx +56 -0
  64. package/template/next/src/proxy.ts +23 -0
  65. package/template/next/src/shared/lib/cn.ts +6 -0
  66. package/template/next/src/shared/server/auth.ts +32 -0
  67. package/template/next/src/shared/server/env.ts +14 -0
  68. package/template/next/src/shared/ui/index.ts +3 -0
  69. package/template/next/tests/e2e/routes.spec.ts +34 -0
  70. package/template/next/tests/unit/create-example.test.ts +55 -0
  71. package/template/next/tsconfig.json +37 -0
  72. package/template/next/vitest.config.ts +19 -0
package/README.md ADDED
@@ -0,0 +1,260 @@
1
+ # 🤖 create-sdd-ai-stack
2
+
3
+ > **O kit de regras de desenvolvimento para agentes de IA, baseado em Spec-Driven Development (SDD).**
4
+ > Stack padrão: **Next.js 16**. Um `npx` e você tem um projeto com regras, arquitetura, design system e SDD prontos.
5
+
6
+ ```bash
7
+ npx create-sdd-ai-stack meu-dashboard
8
+ ```
9
+
10
+ ---
11
+
12
+ ## 🎯 O que é isto
13
+
14
+ Um **template de regras + código** para agentes de IA (Claude Code, Cursor, Copilot, Codex, Gemini CLI, Cline, Windsurf…).
15
+
16
+ O agente abre o projeto, lê **uma** sequência de arquivos, e já sabe:
17
+ o que construir agora, como estruturar, como escrever código, como commitar, quando parar.
18
+
19
+ | Entrega | O que você recebe |
20
+ | --- | --- |
21
+ | **Regras** | `SDD/` com leis do agente, stack, design, arquitetura, SDD e stacks por ferramenta |
22
+ | **Template** | App Next.js 16 completo, com design system já aplicado e buildando |
23
+ | **CLI** | `npx create-sdd-ai-stack <nome>` — cria tudo em 1 comando |
24
+ | **Submodule** | Instala só as regras em qualquer projeto, com atalhos na raiz |
25
+
26
+ ---
27
+
28
+ ## ⚡ Começando
29
+
30
+ ### 1. Projeto novo (recomendado)
31
+
32
+ ```bash
33
+ npx create-sdd-ai-stack meu-app
34
+ cd meu-app
35
+ npm run dev
36
+ ```
37
+
38
+ O que nasce:
39
+
40
+ ```text
41
+ meu-app/
42
+ ├── src/
43
+ │ ├── app/ # rotas (marketing pública + /app logado)
44
+ │ ├── features/ # vertical slice de exemplo (domain/application/infrastructure/ui)
45
+ │ ├── shared/ # design system, lib, server-only
46
+ │ ├── proxy.ts # network boundary + headers
47
+ │ └── app/globals.css# TOKENS DO DESIGN SYSTEM
48
+ ├── tests/ # unit + e2e prontos
49
+ ├── SDD/ # 🧠 as regras
50
+ ├── AGENTS.md # → atalho para ./SDD/AGENTS.md
51
+ ├── CLAUDE.md, GEMINI.md, .cursorrules, .github/copilot-instructions.md, …
52
+ └── package.json
53
+ ```
54
+
55
+ ### 2. Projeto existente (só as regras)
56
+
57
+ ```bash
58
+ # Opção A — submodule (atualiza com git)
59
+ git submodule add https://github.com/marcelinosandroni/sdd-ai-stack.git SDD
60
+ node SDD/SKILLS/install-submodule/install-submodule.mjs
61
+
62
+ # Opção B — CLI
63
+ npx create-sdd-ai-stack . --rules-only
64
+ ```
65
+
66
+ Os atalhos da raiz (`AGENTS.md`, `CLAUDE.md`, `.cursorrules`…) apontam para `./SDD/AGENTS.md`,
67
+ então **todo agente já começa pelo lugar certo** — sem você precisar configurar nada.
68
+
69
+ Atualizar as regras depois:
70
+
71
+ ```bash
72
+ git submodule update --remote --merge SDD
73
+ ```
74
+
75
+ > ⚠️ O `.gitignore` do app gerado protege `.env.local`, `.next/` e `node_modules/`.
76
+ > Nunca commite um `.env` de verdade — só o `.env.example` (que tem placeholders).
77
+
78
+ ### 3. Opções da CLI
79
+
80
+ ```bash
81
+ npx create-sdd-ai-stack meu-app --template next # template (padrão)
82
+ npx create-sdd-ai-stack meu-app --rules-only # só as regras
83
+ npx create-sdd-ai-stack meu-app --install # roda npm install
84
+ npx create-sdd-ai-stack meu-app --git # git init + 1º commit
85
+ npx create-sdd-ai-stack meu-app --submodule # SDD/ como git submodule
86
+ npx create-sdd-ai-stack meu-app --submodule <url> # de um fork seu
87
+ npx create-sdd-ai-stack meu-app --shortcuts stub # sem symlink (Windows sem dev mode)
88
+ ```
89
+
90
+ ---
91
+
92
+ ## 🧠 O mapa das regras (`SDD/`)
93
+
94
+ ```text
95
+ SDD/
96
+ ├── AGENTS.md ⭐ leis + fluxo — LEIA PRIMEIRO
97
+ ├── specs/PLAN.md ⭐ a task AGORA
98
+ ├── APP.md o que é este app
99
+ ├── APP-STACK.md qual stack este app usa
100
+ ├── NEXT.md ⭐ Next.js 16 (stack padrão)
101
+ ├── NODE.md Node.js puro (worker, cron, fila)
102
+ ├── REACT.md React (server-first)
103
+ ├── DESIGN.md 🎨 design system completo
104
+ ├── ARCHITECTURE.md 🏗️ vertical slices
105
+ ├── stacks/ 🧱 por ferramenta
106
+ │ ├── typescript.md tailwind.md shadcn.md
107
+ │ ├── testing.md database.md ai.md
108
+ │ └── git.md ci.md
109
+ ├── specs/ SDD operacional
110
+ │ ├── PLAN.md BACKLOG.md ROADMAP.md
111
+ │ ├── tasks/TASK_TEMPLATE.md
112
+ │ └── history/phases/
113
+ ├── docs/ PRODUCT.md CHANGELOG.md PLANNING.md
114
+ └── SKILLS/ automações (create-feature, install-submodule)
115
+ ```
116
+
117
+ ### Ordem de leitura imposta pelo `AGENTS.md`
118
+
119
+ ```text
120
+ 1. SDD/AGENTS.md leis e fluxo
121
+ 2. SDD/specs/PLAN.md a única task [-]
122
+ 3. SDD/APP.md o que é este app
123
+ 4. SDD/APP-STACK.md qual stack
124
+ 5. SDD/NEXT.md regras da stack
125
+ 6. SDD/DESIGN.md só se mexer em UI
126
+ 7. SDD/stacks/… só a ferramenta que está tocando
127
+ ```
128
+
129
+ > Cada doc de regra tem um **roteador no topo**: "se você está fazendo X, leia §Y".
130
+ > Isso mantém o contexto do agente pequeno — importante, porque contexto longo é onde o agente morre.
131
+
132
+ ---
133
+
134
+ ## 🎨 Design System
135
+
136
+ O `DESIGN.md` implementa o **Executive Engineering**: ardósia profunda (nunca preto puro),
137
+ micro-bordas de 1px, acentos em lime neon `#BAF336` e mint `#34D399`, tipografia tripla
138
+ (**Manrope** estrutural + **JetBrains Mono** técnica + **Playfair Display** editorial), grid de 12 colunas com max 1320px.
139
+
140
+ Os tokens vivem em `src/app/globals.css` (bloco `@theme` do Tailwind v4) e viram utilitários
141
+ (`bg-surface-raised`, `text-text-secondary`, `text-label-mono`, `border-border-subtle`…) +
142
+ primitivos (`btn-primary`, `btn-secondary`, `card`, `card-metric`, `chip`, `field`).
143
+
144
+ **Um lugar só.** Mudou o design? Muda no `@theme`, nunca no componente.
145
+
146
+ ---
147
+
148
+ ## 🏗️ Arquitetura
149
+
150
+ Vertical slices. Uma pasta por domínio, com tudo que aquele domínio precisa:
151
+
152
+ ```text
153
+ src/features/<dominio>/
154
+ ├── domain/ # entidades + contratos (I*.ts) — zero dependência
155
+ ├── application/ # use cases — regra pura, sem Next, sem Prisma
156
+ ├── infrastructure/ # Prisma, HTTP, filas
157
+ ├── container.ts # DI do slice
158
+ ├── queries.ts # entrada de leitura
159
+ ├── actions.ts # entrada de escrita (Server Action)
160
+ └── ui/ # componentes do domínio
161
+ ```
162
+
163
+ Motivo de ser assim: **para entender um requisito você abre uma pasta só** — e o
164
+ `application/` é testável sem mock de infra.
165
+
166
+ ---
167
+
168
+ ## 🚀 Publicar no npm
169
+
170
+ Fluxo único: **você versiona, o GitHub Actions publica.**
171
+
172
+ ```bash
173
+ npm run version:minor # 0.1.17 → 0.2.0 (commita + cria tag v0.2.0)
174
+ git push origin main
175
+ git push origin --tags # ← dispara a publicação
176
+ ```
177
+
178
+ A primeira vez precisa resolver a autenticação. Com **2FA ligado na conta npm**, um token
179
+ comum não publica (`EOTP` — o CI não tem como digitar o OTP). Duas saídas:
180
+
181
+ ```bash
182
+ # A. Recomendado: publica a 1ª versão da sua máquina, ativa OIDC e apaga o token
183
+ npm publish --access public --provenance=false --otp=123456
184
+ # ⚠️ --provenance=false é obrigatório fora do CI: o npm exige OIDC para gerar
185
+ # provenance e falha com "provider: null" se não achar o provedor
186
+ # depois: npmjs.com → create-sdd-ai-stack → Settings → Trusted publishing
187
+ # owner: marcelinosandroni · repo: sdd-ai-stack · workflow: release.yml · allow: npm publish
188
+ gh secret delete NPM_TOKEN --repo marcelinosandroni/sdd-ai-stack
189
+
190
+ # B. Ponte: token granular com "Bypass 2FA" marcado (deprecado pelo npm em jan/2027)
191
+ gh secret set NPM_TOKEN --repo marcelinosandroni/sdd-ai-stack
192
+ ```
193
+
194
+ O workflow escolhe o modo sozinho: **com** `NPM_TOKEN` usa token, **sem** ele usa OIDC.
195
+ Nada de token fica gravado em arquivo.
196
+
197
+ **Guards antes de publicar:** `npm test` (22 testes) · links da doc · tag `vX.Y.Z` bate com
198
+ o `package.json` · 10 arquivos essenciais presentes no tarball · `npm ≥ 11.5.1` · `concurrency` · provenance.
199
+
200
+ 📖 Passo a passo completo (os 3 caminhos de auth, troubleshooting e o caminho stage-only)
201
+ em [`docs/RELEASE.md`](./docs/RELEASE.md).
202
+
203
+ ---
204
+
205
+ ## 🔌 Agentes suportados
206
+
207
+ Os atalhos da raiz são criados para:
208
+
209
+ | Arquivo | Agente |
210
+ | --- | --- |
211
+ | `AGENTS.md` | padrão de mercado (Cursor, Codex, Windsurf, Cline, Gemini) |
212
+ | `CLAUDE.md` | Claude Code |
213
+ | `GEMINI.md` | Gemini CLI |
214
+ | `.cursorrules` | Cursor (formato antigo) |
215
+ | `.windsurfrules` | Windsurf |
216
+ | `.github/copilot-instructions.md` | GitHub Copilot |
217
+ | `.clinerules` | Cline |
218
+
219
+ Todos apontam para `SDD/AGENTS.md`. Nenhuma configuração manual necessária.
220
+
221
+ ---
222
+
223
+ ## 🧪 Verificação
224
+
225
+ ```bash
226
+ npm test # 20 testes da CLI, do scaffold e da documentação
227
+ ```
228
+
229
+ O template em `template/next/` é validado de verdade: `typecheck` + `lint` + `test` + `test:e2e` + `build`.
230
+
231
+ ---
232
+
233
+ ## 📚 SKILLS
234
+
235
+ | SKILL | O que faz |
236
+ | --- | --- |
237
+ | `create-feature` | Cria um vertical slice novo com domain/application/container/queries/actions |
238
+ | `install-submodule` | Instala as regras em projeto existente + cria atalhos |
239
+ | `check-docs` | Valida que todo link relativo entre documentos resolve |
240
+
241
+ ---
242
+
243
+ ## 🛡️ Qualidade
244
+
245
+ ```bash
246
+ npm test # 22 testes: CLI, scaffold e integridade da documentação
247
+ node SDD/SKILLS/check-docs/check-docs.mjs # 29 documentos, links relativos
248
+ npm run check:pack # confere o que vai para o npm (71 arquivos, ~62 kB)
249
+ ```
250
+
251
+ O template em `template/next/` é validado de verdade: `typecheck` + `lint` + `test` + `test:e2e` + `build`.
252
+ O CI (`.github/workflows/ci.yml`) refaz essa validação a cada push, **gerando o app a partir do próprio template**.
253
+
254
+ ---
255
+
256
+ ## 👨‍💻 Autor
257
+
258
+ **Marcelino Sandroni** — [github.com/marcelinosandroni](https://github.com/marcelinosandroni)
259
+
260
+ MIT License.
@@ -0,0 +1,24 @@
1
+ # 🧩 SKILL: check-docs
2
+
3
+ > Valida que **todo link relativo entre documentos** resolve. Roda no hook de commit
4
+ > e no CI para uma regra nunca apontar para arquivo morto.
5
+
6
+ ## ▶️ Uso
7
+
8
+ ```bash
9
+ node SDD/SKILLS/check-docs/check-docs.mjs
10
+ node SDD/SKILLS/check-docs/check-docs.mjs ../outro-projeto
11
+ ```
12
+
13
+ ## 📦 O que verifica
14
+
15
+ - Coleta todo `.md` a partir da raiz do `SDD/`
16
+ - Ignora blocos de código (` ``` ` / `~~~ `) — link ilustrativo dentro de exemplo não conta
17
+ - Ignora `node_modules`, `.next`, `test-results`, `playwright-report`
18
+ - Saída: exit 1 com a lista dos quebrados, ou exit 0 com o total de documentos
19
+
20
+ ## ✅ Quando rodar
21
+
22
+ - Antes de commitar mudança em documentação
23
+ - No CI, junto com os testes
24
+ - Depois de renomear/mover qualquer documento de regra
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SDD SKILL: check-docs
4
+ * Valida que todo link relativo entre documentos markdown resolve.
5
+ *
6
+ * Uso: node SDD/SKILLS/check-docs/check-docs.mjs [raiz]
7
+ */
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+
12
+ const here = path.dirname(fileURLToPath(import.meta.url));
13
+ const root = path.resolve(process.argv[2] ?? path.join(here, "..", ".."));
14
+
15
+ function stripCodeFences(md) {
16
+ return md.replace(/```[\s\S]*?```/g, "").replace(/~~~[\s\S]*?~~~/g, "");
17
+ }
18
+
19
+ /**
20
+ * `template/` é excluído de propósito: o README dele aponta para `./SDD/...`,
21
+ * que só existe DEPOIS do scaffold. Validar aqui daria falso positivo.
22
+ */
23
+ function collectMarkdown(dir) {
24
+ const files = [];
25
+ (function walk(p) {
26
+ if (!fs.existsSync(p)) return;
27
+ const stat = fs.statSync(p);
28
+ if (stat.isDirectory()) {
29
+ const segs = p.split(/[\\/]/);
30
+ if (segs.some((s) => ["node_modules", ".next", "template", "test-results", "playwright-report"].includes(s))) return;
31
+ for (const e of fs.readdirSync(p)) walk(path.join(p, e));
32
+ } else if (/\.md$/.test(p)) {
33
+ files.push(p);
34
+ }
35
+ })(dir);
36
+ return files;
37
+ }
38
+
39
+ const files = collectMarkdown(root);
40
+
41
+ const broken = [];
42
+ const re = /\]\((\.{0,2}\/[^)#\s]+)(?:#[^)]*)?\)/g;
43
+
44
+ for (const file of files) {
45
+ const txt = stripCodeFences(fs.readFileSync(file, "utf8"));
46
+ for (const m of txt.matchAll(re)) {
47
+ const target = path.resolve(path.dirname(file), m[1]);
48
+ if (!fs.existsSync(target)) broken.push(` ${path.relative(root, file)} -> ${m[1]}`);
49
+ }
50
+ }
51
+
52
+ if (broken.length) {
53
+ console.error(`\n✖ ${broken.length} link(s) quebrado(s):\n${broken.join("\n")}\n`);
54
+ process.exit(1);
55
+ }
56
+ console.log(`✓ ${files.length} documentos, todos os links relativos resolvem.`);
@@ -0,0 +1,40 @@
1
+ # 🧩 SKILL: create-feature
2
+
3
+ > Cria um **vertical slice** novo em `src/features/<nome>/` já com domain, application,
4
+ > infrastructure, container, queries e actions seguindo [SDD/ARCHITECTURE.md](../../ARCHITECTURE.md).
5
+
6
+ ## 🎯 Quando usar
7
+
8
+ Toda vez que começa uma feature nova. Antes de escrever arquivo na mão, rode isto.
9
+
10
+ ## ▶️ Uso
11
+
12
+ ```bash
13
+ node SDD/SKILLS/create-feature/create-feature.mjs billing
14
+ ```
15
+
16
+ > Alternativa em bash: `bash SDD/SKILLS/create-feature.sh billing`
17
+
18
+ ## 📦 O que é criado
19
+
20
+ ```text
21
+ src/features/billing/
22
+ ├── domain/
23
+ │ ├── IBillingRepository.ts # contrato (interface, sem dep externa)
24
+ │ └── billing.schema.ts # Zod na fronteira
25
+ ├── application/
26
+ │ └── create-billing.usecase.ts # regra de negócio pura
27
+ ├── infrastructure/ # (vazio — você implementa o repositório)
28
+ ├── container.ts # DI do slice
29
+ ├── queries.ts # entrada de leitura
30
+ ├── actions.ts # Server Action: auth → zod → authz → use case → cache
31
+ └── ui/ # componentes do domínio
32
+ ```
33
+
34
+ ## ✅ Checklist depois de rodar
35
+
36
+ - [ ] Implementar `infrastructure/` (Prisma/API) satisfazendo a interface
37
+ - [ ] Escrever teste unit do use case em `tests/unit/`
38
+ - [ ] Registrar a task em `SDD/specs/PLAN.md` (`[-]`)
39
+ - [ ] Criar a rota em `src/app/` **só roteando** para o slice
40
+ - [ ] `npm run typecheck && npm run test:unit && npm run test:e2e`
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SKILL: create-feature (versão multiplataforma, espelha create-feature.sh)
4
+ * Uso: node SDD/SKILLS/create-feature/create-feature.mjs <nome-do-slice>
5
+ */
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+
9
+ const raw = process.argv[2];
10
+ if (!raw) {
11
+ console.error("Uso: node create-feature.mjs <nome-do-slice>");
12
+ process.exit(1);
13
+ }
14
+
15
+ const name = raw.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-");
16
+ if (!name) {
17
+ console.error("✖ Nome inválido.");
18
+ process.exit(1);
19
+ }
20
+
21
+ const Pascal = name
22
+ .split(/[-_\s]+/)
23
+ .filter(Boolean)
24
+ .map((w) => w[0].toUpperCase() + w.slice(1))
25
+ .join("");
26
+
27
+ const dir = path.resolve(process.cwd(), "src", "features", name);
28
+ if (fs.existsSync(dir)) {
29
+ console.error(`✖ Já existe: ${dir}`);
30
+ process.exit(1);
31
+ }
32
+
33
+ for (const sub of ["domain", "application", "infrastructure", "ui"]) {
34
+ fs.mkdirSync(path.join(dir, sub), { recursive: true });
35
+ }
36
+
37
+ const write = (rel, body) => {
38
+ const p = path.join(dir, rel);
39
+ fs.mkdirSync(path.dirname(p), { recursive: true });
40
+ fs.writeFileSync(p, body, "utf8");
41
+ };
42
+
43
+ write(`domain/I${Pascal}Repository.ts`, `export interface I${Pascal}Repository {
44
+ // TODO: contratos do domínio. Sem dependência externa.
45
+ }
46
+ `);
47
+
48
+ write(`domain/${name}.schema.ts`, `import { z } from "zod";
49
+
50
+ export const ${Pascal}Schema = z.object({
51
+ // TODO: campos + validações
52
+ });
53
+
54
+ export type ${Pascal}Input = z.infer<typeof ${Pascal}Schema>;
55
+ `);
56
+
57
+ write(`application/create-${name}.usecase.ts`, `import type { ${Pascal}Input } from "../domain/${name}.schema";
58
+ import type { I${Pascal}Repository } from "../domain/I${Pascal}Repository";
59
+
60
+ export class Create${Pascal}UseCase {
61
+ constructor(private readonly repo: I${Pascal}Repository) {}
62
+
63
+ async execute(input: ${Pascal}Input) {
64
+ // TODO: regra de negócio pura. Sem Next, sem Prisma.
65
+ throw new Error("not implemented");
66
+ }
67
+ }
68
+ `);
69
+
70
+ write("container.ts", `import "server-only";
71
+ import { Create${Pascal}UseCase } from "./application/create-${name}.usecase";
72
+ import type { I${Pascal}Repository } from "./domain/I${Pascal}Repository";
73
+
74
+ export function create${Pascal}UseCases(repo: I${Pascal}Repository) {
75
+ return {
76
+ create${Pascal}: new Create${Pascal}UseCase(repo),
77
+ };
78
+ }
79
+ `);
80
+
81
+ write("queries.ts", `import "server-only";
82
+ // TODO: leituras do domínio. Marque com 'use cache' quando fizer sentido.
83
+ // Ver SDD/NEXT.md §4 e §6.
84
+
85
+ export async function list${Pascal}() {
86
+ // TODO
87
+ throw new Error("not implemented");
88
+ }
89
+ `);
90
+
91
+ write("actions.ts", `"use server";
92
+ import { revalidatePath, updateTag } from "next/cache";
93
+ import { z } from "zod";
94
+ import { create${Pascal}UseCases } from "./container";
95
+ import { ${Pascal}Schema } from "./domain/${name}.schema";
96
+
97
+ export type ${Pascal}ActionState = {
98
+ ok: boolean;
99
+ errors?: Record<string, string[]>;
100
+ error?: string;
101
+ };
102
+
103
+ export async function create${Pascal}Action(
104
+ _prev: ${Pascal}ActionState,
105
+ formData: FormData,
106
+ ): Promise<${Pascal}ActionState> {
107
+ // 1. auth 2. zod 3. autorização 4. use case 5. cache
108
+ const parsed = ${Pascal}Schema.safeParse(Object.fromEntries(formData));
109
+ if (!parsed.success) {
110
+ return { ok: false, errors: z.flattenError(parsed.error).fieldErrors };
111
+ }
112
+
113
+ try {
114
+ const { create${Pascal} } = create${Pascal}UseCases(/* repo */ undefined as never);
115
+ await create${Pascal}.execute(parsed.data);
116
+ updateTag("${name}");
117
+ revalidatePath("/");
118
+ return { ok: true };
119
+ } catch {
120
+ return { ok: false, error: "Não foi possível concluir. Tente novamente." };
121
+ }
122
+ }
123
+ `);
124
+
125
+ console.log(`✓ Slice criado em ${path.relative(process.cwd(), dir)}`);
126
+ console.log(" 1. Implemente o repositório em infrastructure/");
127
+ console.log(" 2. Escreva o teste em tests/unit/");
128
+ console.log(" 3. Registre a task em SDD/specs/PLAN.md");
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bash
2
+ # SKILL: create-feature
3
+ # Cria um novo vertical slice em src/features/<nome>/ com a estrutura padrão.
4
+ set -euo pipefail
5
+
6
+ NAME="${1:-}"
7
+ if [ -z "$NAME" ]; then
8
+ echo "Uso: create-feature.sh <nome-do-slice>"
9
+ exit 1
10
+ fi
11
+
12
+ DIR="src/features/${NAME}"
13
+
14
+ if [ -e "$DIR" ]; then
15
+ echo "✖ Já existe: $DIR"
16
+ exit 1
17
+ fi
18
+
19
+ mkdir -p "$DIR"/{domain,application,infrastructure,ui}
20
+
21
+ cat > "$DIR/domain/I$(echo "$NAME" | sed 's/^\(.\)/\U\1/')Repository.ts" <<EOF
22
+ export interface I$(echo "$NAME" | sed 's/^\(.\)/\U\1/')Repository {
23
+ // TODO: contratos do domínio. Sem dependência externa.
24
+ }
25
+ EOF
26
+
27
+ cat > "$DIR/domain/${NAME}.schema.ts" <<EOF
28
+ import { z } from "zod";
29
+
30
+ export const ${NAME^}Schema = z.object({
31
+ // TODO: campos + validações
32
+ });
33
+
34
+ export type ${NAME^}Input = z.infer<typeof ${NAME^}Schema>;
35
+ EOF
36
+
37
+ cat > "$DIR/application/create-${NAME}.usecase.ts" <<EOF
38
+ import type { ${NAME^}Input } from "../domain/${NAME}.schema";
39
+ import type { I${NAME^}Repository } from "../domain/I${NAME^}Repository";
40
+
41
+ export class Create${NAME^}UseCase {
42
+ constructor(private readonly repo: I${NAME^}Repository) {}
43
+
44
+ async execute(input: ${NAME^}Input) {
45
+ // TODO: regra de negócio pura. Sem Next, sem Prisma.
46
+ throw new Error("not implemented");
47
+ }
48
+ }
49
+ EOF
50
+
51
+ cat > "$DIR/container.ts" <<EOF
52
+ import "server-only";
53
+ import { Create${NAME^}UseCase } from "./application/create-${NAME}.usecase";
54
+ import type { I${NAME^}Repository } from "./domain/I${NAME^}Repository";
55
+
56
+ export function create${NAME^}UseCases(repo: I${NAME^}Repository) {
57
+ return {
58
+ create${NAME^}: new Create${NAME^}UseCase(repo),
59
+ };
60
+ }
61
+ EOF
62
+
63
+ cat > "$DIR/queries.ts" <<EOF
64
+ import "server-only";
65
+ // TODO: leituras do domínio. Marque com 'use cache' quando fizer sentido.
66
+ // Ver SDD/NEXT.md §4 e §6.
67
+
68
+ export async function list${NAME^}() {
69
+ // TODO
70
+ throw new Error("not implemented");
71
+ }
72
+ EOF
73
+
74
+ cat > "$DIR/actions.ts" <<EOF
75
+ "use server";
76
+ import { revalidatePath, updateTag } from "next/cache";
77
+ import { z } from "zod";
78
+ import { create${NAME^}UseCases } from "./container";
79
+ import { ${NAME^}Schema } from "./domain/${NAME}.schema";
80
+
81
+ export type ${NAME^}ActionState = {
82
+ ok: boolean;
83
+ errors?: Record<string, string[]>;
84
+ error?: string;
85
+ };
86
+
87
+ export async function create${NAME^}Action(
88
+ _prev: ${NAME^}ActionState,
89
+ formData: FormData,
90
+ ): Promise<${NAME^}ActionState> {
91
+ // 1. auth 2. zod 3. autorização 4. use case 5. cache
92
+ const parsed = ${NAME^}Schema.safeParse(Object.fromEntries(formData));
93
+ if (!parsed.success) {
94
+ return { ok: false, errors: z.flattenError(parsed.error).fieldErrors };
95
+ }
96
+
97
+ try {
98
+ const { create${NAME^} } = create${NAME^}UseCases(/* repo */ undefined as never);
99
+ await create${NAME^}.execute(parsed.data);
100
+ updateTag("${NAME}");
101
+ revalidatePath("/");
102
+ return { ok: true };
103
+ } catch {
104
+ return { ok: false, error: "Não foi possível concluir. Tente novamente." };
105
+ }
106
+ }
107
+ EOF
108
+
109
+ echo "✓ Slice criado em $DIR"
110
+ echo " 1. Implemente o repositório em infrastructure/"
111
+ echo " 2. Escreva o teste em tests/unit/"
112
+ echo " 3. Registre a task em SDD/specs/PLAN.md"
@@ -0,0 +1,42 @@
1
+ # 🧩 SKILL: install-submodule
2
+
3
+ > Instala o core de regras (`SDD/`) em um projeto **existente**, cria os atalhos da raiz
4
+ > e deixa o agente pronto para trabalhar.
5
+
6
+ ## 🎯 Quando usar
7
+
8
+ - Projeto já existe e você **não** quer o template Next.js.
9
+ - Só quer as regras + atalhos, mantendo o código atual intocado.
10
+
11
+ ## ▶️ Uso
12
+
13
+ ```bash
14
+ # Dentro do projeto alvo (ou passe o caminho como 1º argumento)
15
+ node SDD/SKILLS/install-submodule/install-submodule.mjs
16
+
17
+ # Instala em outro diretório
18
+ node SDD/SKILLS/install-submodule/install-submodule.mjs ../meu-projeto
19
+
20
+ # Sem git: cópia local
21
+ node SDD/SKILLS/install-submodule/install-submodule.mjs . --copy
22
+ ```
23
+
24
+ ## 📦 O que faz
25
+
26
+ 1. `git submodule add <repo> SDD` (ou cópia com `--copy`)
27
+ 2. Cria atalhos na raiz: `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `.cursorrules`,
28
+ `.windsurfrules`, `.github/copilot-instructions.md`, `.clinerules`
29
+ - tenta **symlink**; se o SO bloquear, grava um **stub** com o mesmo conteúdo da regra
30
+ 3. Preserva arquivos que já existam (não sobrescreve)
31
+
32
+ ## 🔄 Atualizar depois
33
+
34
+ ```bash
35
+ git submodule update --remote --merge SDD
36
+ git add SDD && git commit -m "chore(sdd): atualiza core"
37
+ ```
38
+
39
+ ## ⚠️ Pré-requisitos
40
+
41
+ - Projeto precisa ser um repositório git (para o modo submodule).
42
+ - `git` no PATH.