@brunosps00/dev-workflow 1.7.0 → 2.0.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-plugin/plugin.json +2 -2
- package/CHANGELOG.md +201 -0
- package/README.md +2 -2
- package/lib/agents.js +6 -1
- package/lib/init.js +14 -0
- package/lib/install-deps.js +15 -0
- package/lib/install-open-design.js +39 -0
- package/lib/install-state.js +8 -4
- package/lib/utils.js +46 -6
- package/package.json +3 -2
- package/scaffold/agents/core/dw-build-fixer.md +0 -1
- package/scaffold/agents/core/dw-code-explorer.md +0 -1
- package/scaffold/agents/core/dw-code-reviewer.md +0 -1
- package/scaffold/agents/core/dw-planner.md +0 -1
- package/scaffold/agents/core/dw-test-author.md +0 -1
- package/scaffold/agents/csharp/dw-csharp-reviewer.md +0 -1
- package/scaffold/agents/csharp/dw-dotnet-build-fixer.md +0 -1
- package/scaffold/agents/frontend/dw-qa-runner.md +0 -1
- package/scaffold/agents/python/dw-python-build-fixer.md +0 -1
- package/scaffold/agents/python/dw-python-reviewer.md +0 -1
- package/scaffold/agents/rust/dw-rust-build-fixer.md +0 -1
- package/scaffold/agents/rust/dw-rust-reviewer.md +0 -1
- package/scaffold/agents/security/dw-security-reviewer.md +0 -1
- package/scaffold/agents/security/dw-silent-failure-hunter.md +0 -1
- package/scaffold/agents/typescript/dw-typescript-build-fixer.md +0 -1
- package/scaffold/agents/typescript/dw-typescript-reviewer.md +0 -1
- package/scaffold/config/routing.json +60 -0
- package/scaffold/en/commands/dw-claude-run.md +5 -1
- package/scaffold/en/commands/dw-codex-run.md +5 -1
- package/scaffold/en/commands/dw-dockerize.md +14 -7
- package/scaffold/en/commands/dw-generate-pr.md +13 -0
- package/scaffold/en/commands/dw-new-project.md +34 -30
- package/scaffold/en/commands/dw-run.md +1 -1
- package/scaffold/en/templates/project-onepager.md +16 -14
- package/scaffold/en/templates/task-template.md +1 -1
- package/scaffold/en/templates/tasks-template.md +7 -5
- package/scaffold/pt-br/commands/dw-claude-run.md +5 -1
- package/scaffold/pt-br/commands/dw-codex-run.md +5 -1
- package/scaffold/pt-br/commands/dw-dockerize.md +14 -7
- package/scaffold/pt-br/commands/dw-generate-pr.md +13 -0
- package/scaffold/pt-br/commands/dw-new-project.md +34 -30
- package/scaffold/pt-br/commands/dw-plan.md +1 -1
- package/scaffold/pt-br/commands/dw-run.md +1 -1
- package/scaffold/pt-br/templates/project-onepager.md +16 -14
- package/scaffold/pt-br/templates/task-template.md +1 -1
- package/scaffold/pt-br/templates/tasks-template.md +7 -5
- package/scaffold/skills/docker-compose-recipes/SKILL.md +4 -5
- package/scaffold/skills/docker-compose-recipes/references/compose-composition.md +6 -6
- package/scaffold/skills/docker-compose-recipes/references/env-conventions.md +18 -9
- package/scaffold/skills/docker-compose-recipes/references/healthcheck-patterns.md +4 -5
- package/scaffold/skills/docker-compose-recipes/references/prod-vs-dev.md +7 -2
- package/scaffold/skills/docker-compose-recipes/services/elasticsearch.yml +3 -3
- package/scaffold/skills/docker-compose-recipes/services/mailpit.yml +4 -4
- package/scaffold/skills/docker-compose-recipes/services/meilisearch.yml +2 -2
- package/scaffold/skills/docker-compose-recipes/services/minio.yml +8 -4
- package/scaffold/skills/docker-compose-recipes/services/mysql.yml +4 -4
- package/scaffold/skills/docker-compose-recipes/services/postgres.yml +2 -2
- package/scaffold/skills/docker-compose-recipes/services/rabbitmq.yml +3 -3
- package/scaffold/skills/docker-compose-recipes/services/typesense.yml +3 -3
- package/scaffold/skills/dw-cli-run/SKILL.md +42 -38
- package/scaffold/skills/dw-cli-run/references/dispatch-tuning.md +85 -0
- package/scaffold/skills/dw-execute-phase/SKILL.md +4 -2
- package/scaffold/skills/dw-execute-phase/agents/executor.md +4 -2
- package/scaffold/skills/dw-execute-phase/agents/plan-checker.md +9 -7
- package/scaffold/skills/dw-execute-phase/references/atomic-commits.md +12 -8
- package/scaffold/skills/dw-execute-phase/references/plan-verification.md +6 -4
- package/scaffold/skills/docker-compose-recipes/services/mailhog.yml +0 -23
|
@@ -129,10 +129,12 @@ Cada opcao lista estimativa de tamanho final, notas de attack surface, debug-abi
|
|
|
129
129
|
|
|
130
130
|
Apresente os servicos detectados na Fase 0.3 como checklist. Usuario pode:
|
|
131
131
|
- **Aceitar** — incluir todos os detectados no `docker-compose.dev.yml`
|
|
132
|
-
- **Adicionar** — incluir extras (ex.:
|
|
132
|
+
- **Adicionar** — incluir extras (ex.: Mailpit se SMTP usado em codigo, Jaeger se OTel)
|
|
133
133
|
- **Remover** — dropar um detectado (ex.: Postgres gerenciado em dev tambem)
|
|
134
134
|
|
|
135
|
-
Sempre ofereca
|
|
135
|
+
Sempre ofereca Mailpit se algum lib de envio de email foi detectada e nao tem servico de email no dev.
|
|
136
|
+
|
|
137
|
+
Se pgvector for detectado no projeto, nao ha recipe bundled a que recorrer — ela foi removida porque a imagem carregava CVEs sem correcao upstream. Mantenha a imagem que o projeto ja usa e diga claramente ao usuario que ela precisa de revisao propria: uma imagem reconstruida, ou um Postgres gerenciado com a extensao `vector` habilitada. Nao troque a imagem por conta propria.
|
|
136
138
|
|
|
137
139
|
#### 1.4 Preview de arvore de arquivos
|
|
138
140
|
|
|
@@ -163,8 +165,11 @@ Sem aprovacao: escreve relatorio (Fase 3 com `status: PLANNED`) e para.
|
|
|
163
165
|
**`docker-compose.dev.yml`**:
|
|
164
166
|
- Componha blocos de `.agents/skills/docker-compose-recipes/services/*.yml` segundo `references/compose-composition.md`.
|
|
165
167
|
- Adicione service(s) do app no fim: `build: { context: ., dockerfile: Dockerfile.dev }`, `volumes` para hot reload (bind mount do source, anonymous volume para `node_modules`/`__pycache__`), `env_file: .env`, `depends_on` com `condition: service_healthy` segundo `references/healthcheck-patterns.md`.
|
|
168
|
+
- Preserve a tag da imagem de cada recipe (NAO converta nenhuma para digest — digest congela a base e nunca alcanca um rebuild de seguranca), as vars de credencial obrigatorias e os binds em `127.0.0.1`. As portas loopback mantem intencionalmente a topologia `apps no host` funcionando.
|
|
166
169
|
- Header: `# Generated by /dw-dockerize on YYYY-MM-DD`.
|
|
167
170
|
|
|
171
|
+
**`.env.example`**: emita toda var de credencial sem valor funcional (as recipes usam `${VAR:?}`, entao o Compose recusa subir sem valor). Depois da copia para `.env`, exija que o usuario defina valores locais unicos e gerados antes de rodar Compose. URLs das apps usam `localhost` quando apps rodam no host e DNS do servico quando rodam no Compose.
|
|
172
|
+
|
|
168
173
|
**`Dockerfile.dev`** (multi-stage NAO obrigatorio em dev — single stage tudo bem):
|
|
169
174
|
|
|
170
175
|
| Stack | Forma |
|
|
@@ -176,7 +181,7 @@ Sem aprovacao: escreve relatorio (Fase 3 com `status: PLANNED`) e para.
|
|
|
176
181
|
|
|
177
182
|
**`.dockerignore`** dev: exclua `.git`, `node_modules`, `target`, `dist`, `.dw`, `.agents`, `*.md` (exceto README.md).
|
|
178
183
|
|
|
179
|
-
**README.md secao "Local Dev"** (anexada): tabela de portas dos servicos, credenciais
|
|
184
|
+
**README.md secao "Local Dev"** (anexada): tabela de portas dos servicos, requisitos de credenciais do `.env.example` sem senhas funcionais, os 4 comandos `dev:*`.
|
|
180
185
|
|
|
181
186
|
#### 2.2 Artefatos `--prod`
|
|
182
187
|
|
|
@@ -217,7 +222,8 @@ Requisitos chave (toda linguagem):
|
|
|
217
222
|
- `restart: always`.
|
|
218
223
|
- Network interna. SEM portas publicas exceto via reverse proxy.
|
|
219
224
|
- Secrets via bloco `secrets:` ou manager externo.
|
|
220
|
-
- Drope servicos so-de-dev (sem
|
|
225
|
+
- Drope servicos so-de-dev (sem Mailpit, Mailpit, smtp4dev, LocalStack, MinIO a menos que explicitamente preciso em prod).
|
|
226
|
+
- Para busca vetorial, use imagem revisada separadamente ou servico Postgres gerenciado com a extensao `vector`; este projeto nao distribui imagem pgvector validada.
|
|
221
227
|
|
|
222
228
|
**`.dockerignore`** prod: mais restritivo que dev. Exclua testes, `tests/`, `.github/`, `.dw/`, `.agents/`, todo markdown exceto licenca.
|
|
223
229
|
|
|
@@ -234,6 +240,7 @@ Leia `Dockerfile` e composes existentes. Aplique checks de `security-review/infr
|
|
|
234
240
|
- Compose: servicos sem healthcheck? (flag)
|
|
235
241
|
- Compose: servicos sem `restart` policy? (flag)
|
|
236
242
|
- Compose: bind mounts em compose prod? (flag CRITICAL se `prod` no nome do arquivo)
|
|
243
|
+
- Compose: alguma imagem pinada por digest, ou credencial com default funcional? (flag CRITICAL — ambos bloqueiam rebuild da base ou distribuem credencial usavel)
|
|
237
244
|
|
|
238
245
|
Aplique `dw-review-rigor`: dedupe padroes repetidos, signal-over-volume em nits de estilo.
|
|
239
246
|
|
|
@@ -257,7 +264,7 @@ mode: <dev|prod|both|audit|dry-run>
|
|
|
257
264
|
languages: [...]
|
|
258
265
|
frameworks: { web: '...', api: '...' }
|
|
259
266
|
services_detected: [postgres, redis, ...]
|
|
260
|
-
services_added: [
|
|
267
|
+
services_added: [mailpit, ...]
|
|
261
268
|
base_image_strategy: <conservative|balanced|bold>
|
|
262
269
|
---
|
|
263
270
|
```
|
|
@@ -272,7 +279,7 @@ Secoes:
|
|
|
272
279
|
6. **Files Created** — tabela com path + bytes + papel.
|
|
273
280
|
7. **Audit Findings** (so `--audit`) — tabela de issues com severidade, file:line, recomendacao.
|
|
274
281
|
8. **Next Steps:**
|
|
275
|
-
- Para `--dev`: `cp .env.example .env` (se faltar), `docker compose -f docker-compose.dev.yml up -d`, depois smoke test do app.
|
|
282
|
+
- Para `--dev`: `cp .env.example .env` (se faltar), defina cada secret obrigatorio como `POSTGRES_PASSWORD` com valor local unico, rode `docker compose -f docker-compose.dev.yml up -d`, depois smoke test do app.
|
|
276
283
|
- Para `--prod`: build local primeiro (`docker build -t <name>:dev .`), rode `/dw-secure-audit` no Dockerfile e compose, depois push pro registry.
|
|
277
284
|
- Para `--audit`: aplique fixes manualmente ou rode com `--mode=force-overwrite`.
|
|
278
285
|
- Sempre: rode `/dw-secure-audit --plan` antes de promover a imagem para prod.
|
|
@@ -293,7 +300,7 @@ Secoes:
|
|
|
293
300
|
- <critical>Nunca sobrescreva em silencio. Se `Dockerfile`/`docker-compose.*.yml`/`.dockerignore` existe, default para `--audit`.</critical>
|
|
294
301
|
- <critical>Imagens prod NUNCA incluem secrets, tooling SDK de dev, source nao compilado, ou fixtures de teste.</critical>
|
|
295
302
|
- <critical>Imagens prod SEMPRE rodam como usuario nao-root.</critical>
|
|
296
|
-
- <critical>Compose prod NUNCA inclui
|
|
303
|
+
- <critical>Compose prod NUNCA inclui Mailpit, Mailpit, smtp4dev, LocalStack, ou servicos so-de-dev.</critical>
|
|
297
304
|
- <critical>Se `--audit` acha CRITICAL (secrets em ENV, root user, portas publicas em data tier), Next Steps lista o fix como REQUIRED antes de deploy.</critical>
|
|
298
305
|
- NAO use tag `:latest` em lugar nenhum.
|
|
299
306
|
- NAO execute comandos compose deste comando — gere arquivos, o usuario roda `docker compose up`.
|
|
@@ -106,6 +106,19 @@
|
|
|
106
106
|
|
|
107
107
|
3. **Instruir o usuário** a colar o body (Ctrl+V) no campo de descrição
|
|
108
108
|
|
|
109
|
+
### 6. Registrar a PR de volta na spec
|
|
110
|
+
|
|
111
|
+
A URL da PR só existe depois que o usuário clica em "Create". Assim que existir, escreva de volta — senão nada do lado `.dw/` registra qual PR entregou o trabalho, e a trilha termina na branch.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Caminho rápido: resolve depois que a PR existe. Precisa do GitHub CLI; pule em silêncio se ausente.
|
|
115
|
+
gh pr view --json url -q .url 2>/dev/null
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- Se resolver uma URL, anexe na seção `## Related` do PRD como `- PR: <url>`.
|
|
119
|
+
- Se `gh` não existir ou a PR ainda não foi criada, imprima a linha exata para o usuário colar e siga. **Nunca bloqueie o comando nisso** — é registro, não gate.
|
|
120
|
+
- Para branches de bugfix, anexe a mesma linha em `.dw/bugfixes/<NNN-slug>/SUMMARY.md` sob `## Related`.
|
|
121
|
+
|
|
109
122
|
## Template da PR (copiar para clipboard)
|
|
110
123
|
|
|
111
124
|
```markdown
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<system_instructions>
|
|
2
|
-
Voce e o lider de bootstrap de workspace do dev-workflow. Sua funcao e pegar um diretorio vazio
|
|
2
|
+
Voce e o lider de bootstrap de workspace do dev-workflow. Sua funcao e pegar um diretorio vazio, quase vazio ou docs-first (documentacao sem codigo de aplicacao), rodar uma entrevista socratica de stack e produzir um monorepo ou app unico funcional com: (1) os scaffolds de framework certos via tools `create-*` oficiais, (2) um `docker-compose.dev.yml` cobrindo cada dependencia de dev escolhida (db, cache, fila, email, storage, search, observability, proxy), (3) `.env.example`, scripts, `.gitignore`, `.dockerignore`, GitHub Action, README, e (4) um `.dw/rules/index.md` semeado.
|
|
3
3
|
|
|
4
4
|
<critical>Este comando RODA APOS `npx dev-workflow init` ja ter populado o `.dw/`. Se `.dw/commands/` nao existir no diretorio alvo, aborte com: "Rode `npx @brunosps00/dev-workflow init` primeiro, depois reinvoque /dw-new-project."</critical>
|
|
5
5
|
<critical>NUNCA toque arquivos fora do diretorio do novo projeto. A entrevista captura `{{TARGET_DIR}}`; toda escrita fica escopada ali.</critical>
|
|
6
6
|
<critical>A Fase 3 (execucao) so roda apos o usuario aprovar explicitamente o plano apresentado na Fase 2. Sem flag de bypass.</critical>
|
|
7
|
-
<critical>
|
|
7
|
+
<critical>Mailpit e o DEFAULT para email-em-dev. O usuario tem que optar OUT explicitamente antes de qualquer outro destino SMTP ser ligado em dev.</critical>
|
|
8
8
|
|
|
9
9
|
## Quando Usar
|
|
10
10
|
|
|
11
|
-
- Comecando um projeto novo de diretorio vazio e voce quer as convencoes do dev-workflow, infra containerizada e CI prontos do dia 1
|
|
11
|
+
- Comecando um projeto novo de diretorio vazio ou docs-first e voce quer as convencoes do dev-workflow, infra containerizada e CI prontos do dia 1
|
|
12
12
|
- Substituindo o ritual manual de `pnpm create next-app && create vite ...` por uma entrevista guiada que captura o ambiente de dev inteiro
|
|
13
13
|
- Subindo uma sandbox de aprendizado onde voce quer um stack realista (db + cache + email + observability) sem 30 minutos de YAML
|
|
14
|
-
- NAO use para adicionar servicos a um projeto
|
|
14
|
+
- NAO use para adicionar servicos a um projeto que ja tenha manifests ou codigo de aplicacao — use `/dw-dockerize --audit`
|
|
15
15
|
- NAO use para adicionar app novo dentro de um monorepo existente — outra release vai cobrir isso
|
|
16
16
|
- NAO substitui `/dw-plan prd` — este aqui gera o workspace, nao a spec do produto
|
|
17
17
|
|
|
@@ -52,7 +52,7 @@ Execute as fases em ordem. A Fase 3 so roda apos a aprovacao do usuario no fim d
|
|
|
52
52
|
1. Verifique se `.dw/commands/` existe em `{{TARGET_DIR}}`. Se nao, aborte com a mensagem acima.
|
|
53
53
|
2. Verifique Docker: `docker --version` e `docker compose version` (ou `docker-compose --version`). Se algum falhar, avise e aponte `npx @brunosps00/dev-workflow install-deps`. NAO aborte — o usuario pode querer um `--dry-run` mesmo sem Docker.
|
|
54
54
|
3. Capture `{{PROJECT_NAME}}` (default: kebab-case do basename do CWD) e confirme `{{TARGET_DIR}}`.
|
|
55
|
-
4.
|
|
55
|
+
4. Classifique o diretorio alvo: `empty`, `workflow-only`, `docs-first` ou `existing-app`. `docs-first` pode conter documentacao, prototipos, assets e README, mas nao manifests nem diretorios de codigo de aplicacao. Liste os paths que serao preservados e peca confirmacao. Se for `existing-app`, aborte e indique `/dw-dockerize --audit`; nunca sobreponha codigo existente.
|
|
56
56
|
|
|
57
57
|
Emita VERIFICATION REPORT da Fase 0 (versao do Docker capturada, estado do diretorio).
|
|
58
58
|
|
|
@@ -68,21 +68,21 @@ Use `AskUserQuestion` quando disponivel; senao prompts numerados. Pergunte em **
|
|
|
68
68
|
2. **Linguagem(s)**: TypeScript/JavaScript, Python, C#, Rust (por app)
|
|
69
69
|
3. **Framework por camada** (lista curada — recuse fora dela):
|
|
70
70
|
- **Frontend**: Next.js (app router), Vite + React (template TS)
|
|
71
|
-
- **Backend**: FastAPI (Python), ASP.NET Core minimal API (C#), Axum (Rust)
|
|
72
|
-
- **Fullstack
|
|
71
|
+
- **Backend**: NestJS ou Fastify (Node TS), FastAPI (Python), ASP.NET Core minimal API (C#), Axum (Rust)
|
|
72
|
+
- **Fullstack**: T3 stack (bundle unico), Next.js + NestJS ou Next.js + FastAPI (apps separados em monorepo)
|
|
73
73
|
4. **Package manager** (SEM default — perguntar explicitamente):
|
|
74
74
|
- Node: npm / pnpm / yarn
|
|
75
75
|
- Python: poetry / uv / pip + venv
|
|
76
76
|
- .NET: dotnet (built-in)
|
|
77
77
|
- Rust: cargo (built-in)
|
|
78
|
-
5. **Se fullstack** —
|
|
78
|
+
5. **Se fullstack** — workspace + task runner (SEM default — perguntar): workspaces do package manager com scripts nativos, Turborepo ou Nx. Registre combinacoes como `pnpm workspaces + Turborepo`.
|
|
79
79
|
|
|
80
80
|
#### Camada B — Infra (so pergunte o que cabe na forma)
|
|
81
81
|
|
|
82
|
-
6. **Database**: Postgres / MySQL / SQLite (arquivo, sem service) / MongoDB (fora do escopo dos compose recipes — anote e siga sem service se escolhido) / nenhum
|
|
82
|
+
6. **Database**: Postgres / MySQL / SQLite (arquivo, sem service) / MongoDB (fora do escopo dos compose recipes — anote e siga sem service se escolhido) / nenhum. Nao ha recipe bundled de pgvector: a imagem carregava CVEs sem correcao upstream e nenhum artefato bundled conseguia limpa-las. Se o projeto precisar de busca vetorial, anote e deixe o usuario escolher uma imagem revisada separadamente ou um Postgres gerenciado com a extensao habilitada.
|
|
83
83
|
7. **Cache**: Redis / Memcached / nenhum
|
|
84
|
-
8. **Fila / message broker**: BullMQ (so Node), Celery (so Python), RabbitMQ (qualquer), LocalStack SQS (qualquer), nenhum. Se escolheu, pergunte tambem se vai ter workers async.
|
|
85
|
-
9. **Email — captura em dev** (default: **
|
|
84
|
+
8. **Fila / message broker**: pg-boss (Node + Postgres, sem service extra), BullMQ (so Node + Redis), Celery (so Python), RabbitMQ (qualquer), LocalStack SQS (qualquer), nenhum. Se escolheu, pergunte tambem se vai ter workers async.
|
|
85
|
+
9. **Email — captura em dev** (default: **Mailpit**, so pergunte se quer override): Mailpit / smtp4dev / pular
|
|
86
86
|
10. **Email — destino em prod** (so pergunte se quer email): SMTP relay / SendGrid / Resend / Postmark / SES / pular
|
|
87
87
|
11. **Object storage**: S3 (real, sem service) / MinIO (dev) / GCS (sem service) / nenhum
|
|
88
88
|
12. **Search**: Meilisearch / Typesense / Elasticsearch / nenhum
|
|
@@ -93,7 +93,8 @@ Use `AskUserQuestion` quando disponivel; senao prompts numerados. Pergunte em **
|
|
|
93
93
|
#### Camada C — Tooling
|
|
94
94
|
|
|
95
95
|
16. **Auth** (so pergunte se aplicavel ao stack):
|
|
96
|
-
- Next.js:
|
|
96
|
+
- Next.js: Auth.js / OIDC generico / Clerk / JWT custom / nenhum
|
|
97
|
+
- NestJS: OIDC generico / Passport JWT / auth custom / nenhum
|
|
97
98
|
- FastAPI: fastapi-users / authlib / JWT custom / nenhum
|
|
98
99
|
- ASP.NET: Identity built-in / IdentityServer / JWT custom / nenhum
|
|
99
100
|
- Axum: tower-cookies + jsonwebtoken / custom / nenhum
|
|
@@ -102,7 +103,8 @@ Use `AskUserQuestion` quando disponivel; senao prompts numerados. Pergunte em **
|
|
|
102
103
|
- Python: Ruff + Black / Ruff so
|
|
103
104
|
- C#: dotnet format
|
|
104
105
|
- Rust: rustfmt + clippy (default)
|
|
105
|
-
18. **
|
|
106
|
+
18. **Topologia de dev**: apps no host + infra no Compose / tudo no Compose. Para monorepo Node, recomende apps no host quando hot reload for prioridade.
|
|
107
|
+
19. **CI**: GitHub Actions (sempre seed; usuario pode optar OUT)
|
|
106
108
|
|
|
107
109
|
Guarde todas as respostas para a Fase 2.
|
|
108
110
|
|
|
@@ -110,7 +112,7 @@ Guarde todas as respostas para a Fase 2.
|
|
|
110
112
|
|
|
111
113
|
### Fase 2 — One-Pager + Plano + Gate de Aprovacao
|
|
112
114
|
|
|
113
|
-
1. Renderize `.dw/spec/projects/{{PROJECT_NAME}}.md` a partir de `.dw/templates/project-onepager.md`. Preencha tudo: forma, linguagens, frameworks, tabela de servicos (nome + porta +
|
|
115
|
+
1. Renderize `.dw/spec/projects/{{PROJECT_NAME}}.md` a partir de `.dw/templates/project-onepager.md`. Preencha tudo: forma, linguagens, frameworks, tabela de servicos (nome + porta + requisitos de credenciais, nunca uma senha funcional), diagrama da arquitetura (ASCII), lista de arquivos a gerar, perguntas em aberto.
|
|
114
116
|
2. Monte o plano:
|
|
115
117
|
- Comandos a rodar (em ordem, com argumentos)
|
|
116
118
|
- Arquivos a criar (paths sob `{{TARGET_DIR}}`)
|
|
@@ -133,6 +135,7 @@ Rode nesta ordem. Cada passo emite seu mini-VERIFICATION block.
|
|
|
133
135
|
| Next.js | `pnpm create next-app@latest <dir> --ts --tailwind --eslint --app --import-alias '@/*' --use-pnpm --no-git` |
|
|
134
136
|
| Vite + React | `pnpm create vite@latest <dir> --template react-ts` |
|
|
135
137
|
| T3 | `pnpm dlx create-t3-app@latest <dir> --noGit --CI --tailwind --trpc --prisma --nextAuth --appRouter` |
|
|
138
|
+
| NestJS | `pnpm dlx @nestjs/cli@latest new <dir> --package-manager pnpm --skip-git --strict` |
|
|
136
139
|
| Fastify | `pnpm create fastify@latest <dir>` (corte prompts interativos; se nenhuma flag servir, gere a estrutura inline com `src/server.ts` + `src/routes/` + `package.json`) |
|
|
137
140
|
| FastAPI | SEM `create-*` oficial. Gere inline: `pyproject.toml` (com o package manager escolhido), `app/{routers,models,schemas,deps}/`, `app/main.py`, esqueleto de `tests/` |
|
|
138
141
|
| ASP.NET Core | `dotnet new webapi -n <name> --use-minimal-apis --auth None` (use `--auth Individual` se Identity foi escolhido) |
|
|
@@ -142,12 +145,12 @@ Ajuste a flag de package manager para a escolha do usuario (ex.: `--use-npm`, `-
|
|
|
142
145
|
|
|
143
146
|
Para **fullstack-T3**: e so isso (T3 entrega tudo numa arvore so).
|
|
144
147
|
|
|
145
|
-
Para **fullstack-NextJS+FastAPI**: rode dois scaffolds
|
|
148
|
+
Para **fullstack-NextJS+NestJS** ou **fullstack-NextJS+FastAPI**: rode dois scaffolds diretamente em `apps/web/` e `apps/api/`, sem mover ou apagar documentacao preexistente.
|
|
146
149
|
|
|
147
150
|
#### 3.2 Compor monorepo (so se fullstack)
|
|
148
151
|
|
|
149
152
|
Se fullstack:
|
|
150
|
-
1.
|
|
153
|
+
1. Se um app foi scaffoldado fora do caminho final do workspace, mova-o para `apps/<nome>/`. Apps scaffoldados diretamente em `apps/web/` ou `apps/api/` ja estao no lugar e nao devem ser movidos novamente.
|
|
151
154
|
2. Crie `pnpm-workspace.yaml` (ou equivalente), `package.json` raiz com scripts de workspace, `tsconfig.base.json` se TS config compartilhado.
|
|
152
155
|
3. Se o usuario escolheu Turborepo: adicione `turbo.json` com pipelines `dev`, `build`, `lint`, `test`.
|
|
153
156
|
4. Se o usuario escolheu Nx: rode `pnpm dlx nx@latest init` apos os apps estarem no lugar; integre como projetos Nx.
|
|
@@ -159,12 +162,13 @@ Se fullstack:
|
|
|
159
162
|
- Concatene blocos sob `services:`.
|
|
160
163
|
- Agregue volumes nomeados sob `volumes:`.
|
|
161
164
|
- Resolva colisoes de porta se houver.
|
|
162
|
-
-
|
|
165
|
+
- Se a topologia for `tudo no Compose`, adicione o(s) service(s) do app no fim (build context = `apps/<nome>` ou raiz, Dockerfile.dev, env_file, volumes, depends_on com `condition: service_healthy`). Se for `apps no host`, componha apenas infraestrutura e use endpoints `localhost` nas env vars consumidas pelas apps.
|
|
166
|
+
- Preserve a tag da imagem de cada recipe (NAO converta nenhuma para digest — digest congela a imagem base e nunca alcanca um rebuild de seguranca), as vars de credencial obrigatorias e os binds de porta em `127.0.0.1`. Esses mapeamentos loopback suportam intencionalmente `apps no host`; nao os remova do dev local.
|
|
163
167
|
3. Adicione header: `# Generated by /dw-new-project on YYYY-MM-DD`.
|
|
164
168
|
|
|
165
169
|
#### 3.4 Gerar `.env.example`
|
|
166
170
|
|
|
167
|
-
Consolide cada env var referenciada pelos servicos selecionados (segundo `references/env-conventions.md`). Agrupe por servico. Sempre inclua as URLs derivadas do lado da app (`DATABASE_URL`, `REDIS_URL`, `AMQP_URL`, `SMTP_HOST`/`SMTP_PORT`, `AWS_ENDPOINT_URL`, etc.).
|
|
171
|
+
Consolide cada env var referenciada pelos servicos selecionados (segundo `references/env-conventions.md`). Agrupe por servico. Sempre inclua as URLs derivadas do lado da app (`DATABASE_URL`, `REDIS_URL`, `AMQP_URL`, `SMTP_HOST`/`SMTP_PORT`, `AWS_ENDPOINT_URL`, etc.). Toda var de credencial e emitida vazia no `.env.example` (as recipes usam `${VAR:?}`, entao o Compose recusa subir sem valor real). Exija que o usuario defina valores unicos e gerados no `.env` gitignored antes de rodar Compose. Nunca emita uma senha reutilizavel.
|
|
168
172
|
|
|
169
173
|
#### 3.5 Gerar scripts
|
|
170
174
|
|
|
@@ -214,7 +218,7 @@ Scaffold minimo:
|
|
|
214
218
|
| Database | <db ou n/a> |
|
|
215
219
|
| Cache | <cache ou n/a> |
|
|
216
220
|
| Fila | <fila ou n/a> |
|
|
217
|
-
| Email (dev) | <
|
|
221
|
+
| Email (dev) | <mailpit|smtp4dev|nenhum> |
|
|
218
222
|
| Search | <search ou n/a> |
|
|
219
223
|
| Observability | <observability ou n/a> |
|
|
220
224
|
| Reverse proxy | <traefik|nenhum> |
|
|
@@ -225,12 +229,12 @@ Scaffold minimo:
|
|
|
225
229
|
|
|
226
230
|
## Servicos no docker-compose.dev.yml
|
|
227
231
|
|
|
228
|
-
(tabela dos servicos selecionados com portas e credenciais
|
|
232
|
+
(tabela dos servicos selecionados com portas e requisitos de credenciais; nunca inclua senha funcional)
|
|
229
233
|
|
|
230
234
|
## Convencoes
|
|
231
235
|
|
|
232
236
|
- Veja `.dw/rules/<modulo>.md` apos o `/dw-analyze-project` rodar.
|
|
233
|
-
- Email em dev usa
|
|
237
|
+
- Email em dev usa Mailpit por default; o app NUNCA envia email real em dev.
|
|
234
238
|
- Toda env var vive em `.env` (gitignored); `.env.example` e o template.
|
|
235
239
|
```
|
|
236
240
|
|
|
@@ -238,8 +242,8 @@ Scaffold minimo:
|
|
|
238
242
|
|
|
239
243
|
Gere um README inicial:
|
|
240
244
|
- Nome do projeto + 1 linha de proposito
|
|
241
|
-
- Quick Start (`cp .env.example .env
|
|
242
|
-
- Local Dev (tabela de portas dos servicos selecionados + URLs das UIs + credenciais
|
|
245
|
+
- Quick Start (`cp .env.example .env`, defina cada secret obrigatorio com valor local unico, depois `pnpm install && pnpm dev:up`)
|
|
246
|
+
- Local Dev (tabela de portas dos servicos selecionados + URLs das UIs + requisitos de credenciais; nunca publique senha funcional)
|
|
243
247
|
- Diagrama da arquitetura (ASCII do one-pager)
|
|
244
248
|
- Layout do projeto (arvore dos diretorios top-level)
|
|
245
249
|
- Integracao com dev-workflow (mencione `/dw-plan prd`, `/dw-run`, `/dw-qa`, `/dw-secure-audit --plan`, `/dw-secure-audit`)
|
|
@@ -273,7 +277,7 @@ date: YYYY-MM-DD
|
|
|
273
277
|
shape: <frontend|backend|fullstack>
|
|
274
278
|
languages: [typescript, python, ...]
|
|
275
279
|
frameworks: { web: '...', api: '...' }
|
|
276
|
-
services: [postgres,
|
|
280
|
+
services: [postgres, mailpit, minio, ...]
|
|
277
281
|
package_manager: <pnpm|npm|yarn|poetry|uv|cargo|dotnet>
|
|
278
282
|
monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
279
283
|
---
|
|
@@ -296,13 +300,13 @@ monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
|
296
300
|
| ... | ... | ... |
|
|
297
301
|
|
|
298
302
|
## Servicos Compostos
|
|
299
|
-
<tabela de servicos com porta + URL UI + credenciais
|
|
303
|
+
<tabela de servicos com porta + URL UI + requisitos de credenciais, vinda de .agents/skills/docker-compose-recipes/>
|
|
300
304
|
|
|
301
305
|
## Proximos Passos
|
|
302
|
-
1. `cp .env.example .env
|
|
306
|
+
1. `cp .env.example .env`, gere secrets locais unicos e defina todo valor obrigatorio como `POSTGRES_PASSWORD`.
|
|
303
307
|
2. `pnpm install` (ou seu package manager).
|
|
304
308
|
3. `pnpm dev:up` para subir todos os servicos. Aguarde os healthchecks.
|
|
305
|
-
4. Abra a UI do
|
|
309
|
+
4. Abra a UI do Mailpit em http://localhost:8025 para confirmar a captura de email.
|
|
306
310
|
5. `/dw-plan prd` para a primeira feature.
|
|
307
311
|
6. Apos o primeiro commit substancial, rode `/dw-analyze-project` para enriquecer `.dw/rules/`.
|
|
308
312
|
```
|
|
@@ -320,10 +324,10 @@ monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
|
320
324
|
|
|
321
325
|
- <critical>NUNCA pule o gate de aprovacao da Fase 2. Se rodando em contexto nao-interativo, aborte com: "/dw-new-project exige aprovacao interativa; rerode com --dry-run para so planejar."</critical>
|
|
322
326
|
- <critical>NUNCA rode tools `create-*` fora de `{{TARGET_DIR}}`. CWD de cada comando e o target dir.</critical>
|
|
323
|
-
- <critical>Se
|
|
327
|
+
- <critical>Se Mailpit/smtp4dev foi selecionado, NUNCA tambem ligue um SMTP real em dev. O compose de dev SEMPRE captura.</critical>
|
|
324
328
|
- <critical>Se uma tool `create-*` falha, PARE. Nao siga para gerar compose — scaffold parcial confunde os comandos seguintes.</critical>
|
|
325
329
|
- NAO pin de versao SDK Node/Python/.NET/Rust dentro do projeto a nao ser que o usuario peca; use `package.json` engines / `pyproject.toml` / `global.json` / `rust-toolchain.toml` para indicar intencao sem forcar.
|
|
326
|
-
- NAO baked secrets em arquivo gerado. `.env.example`
|
|
330
|
+
- NAO baked secrets em arquivo gerado. `.env.example` contem defaults nao secretos de dev e chaves secretas obrigatorias vazias; valores reais ficam em `.env` nao versionado.
|
|
327
331
|
|
|
328
332
|
## Tratamento de Erros
|
|
329
333
|
|
|
@@ -332,7 +336,7 @@ monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
|
332
336
|
- Usuario escolhe MongoDB → anote "Recipe MongoDB nao bundled na v0.8.0; vamos adicionar deps de app mas voce vai precisar ligar o servico manualmente". Continue.
|
|
333
337
|
- Usuario escolhe Caddy → idem: anote como nao bundled; siga sem servico no compose.
|
|
334
338
|
- Porta ja ocupada no host → sugira a env var de override e siga; nao escolha outra porta em silencio.
|
|
335
|
-
- Working tree
|
|
339
|
+
- Working tree docs-first → preserve cada path listado e escreva apenas nos novos paths aprovados. Existing app → aborte e indique `/dw-dockerize --audit`.
|
|
336
340
|
|
|
337
341
|
## Integracao com Outros dw-* Commands
|
|
338
342
|
|
|
@@ -113,7 +113,7 @@ Roda em modo padrão OU `plan prd`.
|
|
|
113
113
|
|
|
114
114
|
1. **Coverage matrix sobre as dimensões do PRD** (objetivos, usuários-alvo, limites de escopo, métricas de sucesso, estratégia de rollout, pontos de integração, edge cases). Monte a matriz, credite evidência de handoff alinhado e fatos descobertos do repo, e pergunte SOMENTE as dimensões descobertas — uma decisão por vez, cada uma com resposta recomendada — usando a ferramenta de entrevista estruturada quando disponível (registre o fallback em chat caso contrário). Sem contagem fixa de perguntas; nunca re-pergunte uma decisão resolvida num one-pager alinhado.
|
|
115
115
|
2. **Web search MÍNIMO 3 queries** para padrões de mercado, contexto regulatório, abordagens de competidores quando relevante.
|
|
116
|
-
3. **Constitution alignment.** Cada requisito funcional (
|
|
116
|
+
3. **Constitution alignment.** Cada requisito funcional (RF-N.M) inclui linha `Constitution Alignment: respects P-NNN, P-MMM` OU `no applicable principle: <motivo>`.
|
|
117
117
|
4. **Awareness multi-projeto.** Se feature cruza projetos do workspace, consulte `.dw/rules/integrations.md` e documente escopo na seção "Projetos Impactados".
|
|
118
118
|
5. **Output:** `.dw/spec/prd-<feature-slug>/prd.md`.
|
|
119
119
|
|
|
@@ -75,7 +75,7 @@ Quando disponíveis em `./.agents/skills/`, estas skills são invocadas por task
|
|
|
75
75
|
- Mensagem atômica: `feat(<scope>): <título da task> (#<task-id>)`.
|
|
76
76
|
- Referencie FRs cobertos.
|
|
77
77
|
- Uma task = um commit (exceto se task tem subtask milestones explícitos que ganham commits separados).
|
|
78
|
-
6. **Atualizar tasks.md:** marcar task como `Done`
|
|
78
|
+
6. **Atualizar tasks.md:** marcar `Status` da task como `Done` e escrever o SHA curto (`git rev-parse --short HEAD`) na coluna `Commit`. Esse é o único registro que liga a task ao seu diff — não pule.
|
|
79
79
|
7. **Reportar:** o que foi feito, testes adicionados, o que foi validado.
|
|
80
80
|
|
|
81
81
|
### CONDIÇÕES DE PARADA
|
|
@@ -23,33 +23,35 @@ services: []
|
|
|
23
23
|
|--------|---------|---------------|
|
|
24
24
|
| Forma | frontend / backend / fullstack | [por que essa forma — superficie unica, API para parceiros, etc.] |
|
|
25
25
|
| Frontend | Next.js / Vite+React / n/a | [por que esse framework — SSR, simplicidade SPA, etc.] |
|
|
26
|
-
| Backend | FastAPI / ASP.NET Core minimal / Axum /
|
|
27
|
-
| Database | Postgres / MySQL / SQLite / MongoDB / nenhum | [por que esse DB — relacional,
|
|
26
|
+
| Backend | NestJS / Fastify / FastAPI / ASP.NET Core minimal / Axum / n/a | [por que — expertise do time, ecosystem, alvo de latencia] |
|
|
27
|
+
| Database | Postgres / MySQL / SQLite / MongoDB / nenhum | [por que esse DB — relacional, transacional, etc. Busca vetorial nao tem recipe bundled; nomeie a imagem revisada ou servico gerenciado se o projeto precisar] |
|
|
28
28
|
| Cache | Redis / Memcached / nenhum | [por que ou por que nao] |
|
|
29
|
-
| Fila | BullMQ / Celery / RabbitMQ / LocalStack SQS / nenhum | [por que ou nao + sync vs async workers] |
|
|
30
|
-
| Email — dev |
|
|
29
|
+
| Fila | pg-boss / BullMQ / Celery / RabbitMQ / LocalStack SQS / nenhum | [por que ou nao + sync vs async workers] |
|
|
30
|
+
| Email — dev | Mailpit (default) / smtp4dev / nenhum | [normalmente Mailpit — captura only, nunca envia real] |
|
|
31
31
|
| Email — prod | SMTP / SendGrid / Resend / Postmark / SES / nenhum | [por que esse provider — volume, deliverability, custo] |
|
|
32
32
|
| Object storage | S3 / MinIO (dev) / GCS / nenhum | [por que ou nao] |
|
|
33
33
|
| Search | Meilisearch / Typesense / Elasticsearch / nenhum | [por que esse engine — features, escala, simplicidade] |
|
|
34
34
|
| Observability | Sentry / OTel + Jaeger / nenhum | [por que essa abordagem — so error tracking, tracing completo, etc.] |
|
|
35
35
|
| Reverse proxy | Traefik / Caddy / nenhum | [normalmente so multi-host dev ou prod] |
|
|
36
|
-
| Auth |
|
|
36
|
+
| Auth | Auth.js / OIDC generico / Clerk / fastapi-users / dotnet Identity / JWT custom / nenhum | [por que — social login, B2B, etc.] |
|
|
37
37
|
| Linter / formatter | Biome / ESLint+Prettier / Ruff+Black / dotnet format / cargo fmt+clippy | [preferencia do time] |
|
|
38
38
|
| Package manager | pnpm / npm / yarn / poetry / uv / cargo / dotnet | [preferencia do time] |
|
|
39
|
-
|
|
|
39
|
+
| Workspace + task runner | pnpm workspaces + Turborepo / npm workspaces / Nx / n/a | [so para fullstack — caching/build] |
|
|
40
|
+
| Topologia de dev | apps no host / tudo no Compose | [trade-off de hot reload e paridade] |
|
|
40
41
|
| CI | GitHub Actions / nenhum | [normalmente GitHub Actions; pular so para repos nao-publicos] |
|
|
41
42
|
|
|
42
43
|
## Servicos & Infra
|
|
43
44
|
|
|
44
45
|
[Servicos gerados a partir da skill docker-compose-recipes. Preenchido pelo /dw-new-project.]
|
|
45
46
|
|
|
46
|
-
| Servico | Porta (host) | UI | Credenciais
|
|
47
|
-
|
|
48
|
-
| postgres | 5432 | — | POSTGRES_USER=app, POSTGRES_PASSWORD
|
|
47
|
+
| Servico | Porta (host) | UI | Credenciais |
|
|
48
|
+
|---------|--------------|----|-------------|
|
|
49
|
+
| postgres | 127.0.0.1:5432 | — | POSTGRES_USER=app, POSTGRES_PASSWORD obrigatoria no `.env` (sem default), POSTGRES_DB=app |
|
|
49
50
|
| redis | 6379 | — | (sem auth em dev) |
|
|
50
|
-
|
|
|
51
|
+
| mailpit | 1025 (smtp), 8025 (UI) | http://localhost:8025 | (sem auth) |
|
|
51
52
|
| ... | ... | ... | ... |
|
|
52
53
|
|
|
54
|
+
|
|
53
55
|
## Diagrama da Arquitetura
|
|
54
56
|
|
|
55
57
|
```
|
|
@@ -59,12 +61,12 @@ services: []
|
|
|
59
61
|
[ Browser ] -> [ Next.js (apps/web) ]
|
|
60
62
|
|
|
61
63
|
# Fullstack
|
|
62
|
-
[ Browser ] -> [ Next.js (apps/web) ] -> [
|
|
64
|
+
[ Browser ] -> [ Next.js (apps/web) ] -> [ NestJS (apps/api) ] -> [ Postgres ]
|
|
63
65
|
|-> [ Redis ]
|
|
64
|
-
|-> [
|
|
66
|
+
|-> [ Mailpit ]
|
|
65
67
|
|
|
66
68
|
# Com observability
|
|
67
|
-
... -> [
|
|
69
|
+
... -> [ NestJS ] -> { OTLP } -> [ Jaeger ]
|
|
68
70
|
```
|
|
69
71
|
|
|
70
72
|
## Arquivos Gerados
|
|
@@ -75,7 +77,7 @@ services: []
|
|
|
75
77
|
{{TARGET_DIR}}/
|
|
76
78
|
├── apps/
|
|
77
79
|
│ ├── web/ (criado por `pnpm create next-app`)
|
|
78
|
-
│ └── api/ (
|
|
80
|
+
│ └── api/ (criado por `pnpm dlx @nestjs/cli` ou scaffold escolhido)
|
|
79
81
|
├── packages/
|
|
80
82
|
│ └── shared/ (criado pelo /dw-new-project)
|
|
81
83
|
├── docker-compose.dev.yml (composto a partir de .agents/skills/docker-compose-recipes/)
|
|
@@ -12,7 +12,7 @@ status: pending
|
|
|
12
12
|
|
|
13
13
|
[Breve descrição da tarefa]
|
|
14
14
|
|
|
15
|
-
**Requisitos Funcionais cobertos**: RF
|
|
15
|
+
**Requisitos Funcionais cobertos**: RF-X.Y, RF-X.Z (máximo 2 por task)
|
|
16
16
|
|
|
17
17
|
<requirements>
|
|
18
18
|
[Lista de requisitos obrigatórios]
|
|
@@ -19,11 +19,13 @@ feat/prd-[nome-funcionalidade]
|
|
|
19
19
|
|
|
20
20
|
## Tarefas
|
|
21
21
|
|
|
22
|
-
| Task | Descrição | RFs | Status |
|
|
23
|
-
|
|
24
|
-
| 1.0 | [Título] |
|
|
25
|
-
| 2.0 | [Título] |
|
|
26
|
-
| 3.0 | [Título] |
|
|
22
|
+
| Task | Descrição | RFs | Status | Commit |
|
|
23
|
+
|------|-----------|-----|--------|--------|
|
|
24
|
+
| 1.0 | [Título] | RF-1.1, RF-1.2 | Pendente | — |
|
|
25
|
+
| 2.0 | [Título] | RF-2.1 | Pendente | — |
|
|
26
|
+
| 3.0 | [Título] | RF-3.1, RF-3.2 | Pendente | — |
|
|
27
|
+
|
|
28
|
+
`Commit` guarda o SHA curto escrito de volta pelo `/dw-run` quando a task fecha (passo 6). É o que torna o diff da task localizável depois — deixe `—` até a task commitar.
|
|
27
29
|
|
|
28
30
|
## Progresso
|
|
29
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: docker-compose-recipes
|
|
3
|
-
description: Use for docker-compose service blocks (postgres, redis,
|
|
3
|
+
description: Use for docker-compose service blocks (postgres, redis, mailpit, minio, meilisearch, jaeger, traefik). Invoked by /dw-new-project, /dw-dockerize, or when composing dev/prod compose files.
|
|
4
4
|
allowed-tools:
|
|
5
5
|
- Read
|
|
6
6
|
- Write
|
|
@@ -54,8 +54,7 @@ Each row points to `services/<name>.yml`.
|
|
|
54
54
|
| Memcached 1.6 (alpine) | Cache | `11211` | `services/memcached.yml` |
|
|
55
55
|
| RabbitMQ 3 (management-alpine) | Message broker + UI | `5672`, UI `15672` | `services/rabbitmq.yml` |
|
|
56
56
|
| LocalStack | AWS-compatible local (S3, SQS, SNS, DynamoDB) | `4566` | `services/localstack.yml` |
|
|
57
|
-
|
|
|
58
|
-
| Mailpit | Modern MailHog alternative | SMTP `1025`, UI `8025` | `services/mailpit.yml` |
|
|
57
|
+
| Mailpit | Default email-in-dev (capture only, never sends) | SMTP `1025`, UI `8025` | `services/mailpit.yml` |
|
|
59
58
|
| smtp4dev | Windows-friendly SMTP capture | SMTP `2525`, UI `5000` | `services/smtp4dev.yml` |
|
|
60
59
|
| MinIO | S3-compatible local | API `9000`, UI `9001` | `services/minio.yml` |
|
|
61
60
|
| Meilisearch | Search engine (lightweight) | `7700` | `services/meilisearch.yml` |
|
|
@@ -76,12 +75,12 @@ Each row points to `services/<name>.yml`.
|
|
|
76
75
|
- **Pin major.minor** in every `image:` line. Patch updates are safe; major bumps are deliberate.
|
|
77
76
|
- **Always include healthcheck**. No service is allowed to be opaque about readiness.
|
|
78
77
|
- **Default to dev**. Prod transforms are explicit (see `prod-vs-dev.md`).
|
|
79
|
-
- **Email-in-dev defaults to
|
|
78
|
+
- **Email-in-dev defaults to Mailpit**. The user must opt OUT of capture-only email for dev — never silently route to a real SMTP.
|
|
80
79
|
- **Secrets never in the recipe**. Env vars reference `.env`; defaults in the recipe are OK only for non-secret config.
|
|
81
80
|
|
|
82
81
|
## Inspired by
|
|
83
82
|
|
|
84
|
-
Hand-curated by dev-workflow. Service defaults follow upstream documentation (Docker Hub `postgres`, `redis`, `
|
|
83
|
+
Hand-curated by dev-workflow. Service defaults follow upstream documentation (Docker Hub `postgres`, `redis`, `axllent/mailpit`, `minio/minio`, `getmeili/meilisearch`, `jaegertracing/all-in-one`, `traefik`). Healthcheck patterns adapted from `docker-library/healthcheck` and the official compose docs.
|
|
85
84
|
|
|
86
85
|
## Structured Return
|
|
87
86
|
|
|
@@ -4,7 +4,7 @@ This file describes how `/dw-new-project` and `/dw-dockerize` merge the standalo
|
|
|
4
4
|
|
|
5
5
|
## The merge algorithm
|
|
6
6
|
|
|
7
|
-
1. **Pick the selected services.** From the interview answers (or from stack detection in `dw-dockerize`), get the list of services to include. Example: `[postgres,
|
|
7
|
+
1. **Pick the selected services.** From the interview answers (or from stack detection in `dw-dockerize`), get the list of services to include. Example: `[postgres, mailpit, minio]`.
|
|
8
8
|
2. **Read each `services/<name>.yml`** as a standalone fragment. Each file declares ONE top-level service block (e.g., `postgres:`) plus comments at the bottom describing the volumes block to merge.
|
|
9
9
|
3. **Concatenate under a single `services:` map.** Indent each block under `services:` in the final file. Order does not matter for compose, but for readability sort by tier: storage → cache/queue → search → email → observability → proxy.
|
|
10
10
|
4. **Collect the volumes.** Each recipe's comments list the named volumes it needs. Aggregate them under a top-level `volumes:` block. Example:
|
|
@@ -31,7 +31,7 @@ This file describes how `/dw-new-project` and `/dw-dockerize` merge the standalo
|
|
|
31
31
|
condition: service_healthy
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
8. **
|
|
34
|
+
8. **Apply the selected dev topology.** For `everything in Compose`, add the app service(s) at the end and bind source for hot reload. For `apps on host`, do not generate app services or Dockerfile.dev files; expose only infrastructure ports and point application-facing env vars at `localhost`.
|
|
35
35
|
|
|
36
36
|
## Final file shape
|
|
37
37
|
|
|
@@ -49,8 +49,8 @@ services:
|
|
|
49
49
|
# ... contents from services/redis.yml
|
|
50
50
|
|
|
51
51
|
# --- email-in-dev (capture only) ---
|
|
52
|
-
|
|
53
|
-
# ... contents from services/
|
|
52
|
+
mailpit:
|
|
53
|
+
# ... contents from services/mailpit.yml
|
|
54
54
|
|
|
55
55
|
# --- object storage ---
|
|
56
56
|
minio:
|
|
@@ -72,8 +72,8 @@ services:
|
|
|
72
72
|
condition: service_healthy
|
|
73
73
|
redis:
|
|
74
74
|
condition: service_healthy
|
|
75
|
-
|
|
76
|
-
condition:
|
|
75
|
+
mailpit:
|
|
76
|
+
condition: service_healthy
|
|
77
77
|
minio:
|
|
78
78
|
condition: service_healthy
|
|
79
79
|
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
# Env var conventions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Recipes reference non-secret env vars via `${VAR:-default}` — ports, users, database names. **Every credential uses `${VAR:?error}` instead**, so Compose refuses to start when the value is missing rather than falling back to a value published in this repository. That applies to `postgres`, `mysql`, `elasticsearch`, `meilisearch`, `minio`, and `rabbitmq`; `test/compose-recipe-safety.test.js` enforces it across every recipe.
|
|
4
|
+
|
|
5
|
+
Authenticated services also publish on `127.0.0.1:` only. Docker's `"HOST:CONTAINER"` short form binds every host interface, which turns a local dev credential into a network-reachable one.
|
|
6
|
+
|
|
7
|
+
A project's `.env` is the local source of truth; `.env.example` documents required keys without supplying reusable credentials.
|
|
8
|
+
|
|
9
|
+
[source: https://docs.docker.com/reference/compose-file/interpolation/, version: Compose Specification, retrieved: 2026-07-15]
|
|
4
10
|
|
|
5
11
|
## Naming pattern
|
|
6
12
|
|
|
7
13
|
- **Service-scoped** vars use the upstream image's convention: `POSTGRES_USER`, `MYSQL_ROOT_PASSWORD`, `MEILI_MASTER_KEY`, etc. This avoids surprises when reading the image's documentation.
|
|
8
14
|
- **Application-scoped** vars use a generic name that spans implementations: `DATABASE_URL`, `REDIS_URL`, `SMTP_HOST`, `AWS_ENDPOINT_URL`. The application reads these, not the service-specific ones.
|
|
9
|
-
- **Port overrides** use `<SERVICE>_PORT` (or `<SERVICE>_<ROLE>_PORT` when there are several): `POSTGRES_PORT`, `
|
|
15
|
+
- **Port overrides** use `<SERVICE>_PORT` (or `<SERVICE>_<ROLE>_PORT` when there are several): `POSTGRES_PORT`, `MAILPIT_SMTP_PORT`, `MAILPIT_UI_PORT`, `RABBITMQ_PORT`, `RABBITMQ_UI_PORT`.
|
|
10
16
|
|
|
11
17
|
## Mapping between service vars and app vars
|
|
12
18
|
|
|
@@ -15,19 +21,22 @@ When a project uses Postgres, the `.env.example` should declare BOTH the service
|
|
|
15
21
|
```dotenv
|
|
16
22
|
# Postgres (consumed by the postgres service)
|
|
17
23
|
POSTGRES_USER=app
|
|
18
|
-
|
|
24
|
+
# Required: generate a unique value in .env before running Compose.
|
|
25
|
+
POSTGRES_PASSWORD=
|
|
19
26
|
POSTGRES_DB=app
|
|
20
27
|
POSTGRES_PORT=5432
|
|
21
28
|
|
|
22
|
-
# Application-side connection string
|
|
23
|
-
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@
|
|
29
|
+
# Application-side connection string for apps running on the host
|
|
30
|
+
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/${POSTGRES_DB}
|
|
24
31
|
```
|
|
25
32
|
|
|
26
|
-
Compose performs variable substitution in `.env` references
|
|
33
|
+
Compose performs variable substitution in `.env` references. When the application also runs in Compose, use service DNS such as `postgres`; when applications run on the host, the committed example must use `localhost` and the published host port instead.
|
|
34
|
+
|
|
35
|
+
If a project needs the `vector` extension, there is no bundled recipe for it — use a separately reviewed image or a managed Postgres, with the same connection variables above. `CREATE EXTENSION IF NOT EXISTS vector` belongs in the application's reviewed migrations, never in a container startup script.
|
|
27
36
|
|
|
28
37
|
## What goes in `.env.example` vs `.env`
|
|
29
38
|
|
|
30
|
-
- `.env.example` — committed. Holds
|
|
39
|
+
- `.env.example` — committed. Holds non-secret defaults and empty required secret keys; it never contains a working database password.
|
|
31
40
|
- `.env` — gitignored. Real values for the user's local machine.
|
|
32
41
|
|
|
33
42
|
Never commit a `.env`. Always commit a `.env.example`.
|
|
@@ -41,11 +50,11 @@ Never commit a `.env`. Always commit a `.env.example`.
|
|
|
41
50
|
| Redis URL | `REDIS_URL` | `REDIS_PASSWORD` (if set) |
|
|
42
51
|
| RabbitMQ URL | `AMQP_URL` | `RABBITMQ_USER`, `RABBITMQ_PASSWORD` |
|
|
43
52
|
| AWS-compatible | `AWS_ENDPOINT_URL`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` | LocalStack: `test`/`test`. MinIO: `MINIO_ROOT_USER`, `MINIO_ROOT_PASSWORD` |
|
|
44
|
-
| SMTP | `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_SECURE` | Service hostname (`
|
|
53
|
+
| SMTP | `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_SECURE` | Service hostname (`mailpit`/`smtp4dev`) + recipe's SMTP port |
|
|
45
54
|
| OTel | `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://jaeger:4318` |
|
|
46
55
|
|
|
47
56
|
## Reserved names
|
|
48
57
|
|
|
49
58
|
The recipes use these env var names. Do NOT reuse them for unrelated config:
|
|
50
59
|
|
|
51
|
-
`POSTGRES_*`, `MYSQL_*`, `MEILI_*`, `MINIO_*`, `RABBITMQ_*`, `
|
|
60
|
+
`POSTGRES_*`, `MYSQL_*`, `MEILI_*`, `MINIO_*`, `RABBITMQ_*`, `MAILPIT_*`, `SMTP4DEV_*`, `JAEGER_*`, `TRAEFIK_*`, `LOCALSTACK_*`, `ELASTIC_*`, `TYPESENSE_*`, `MEMCACHED_*`, `REDIS_*`.
|
|
@@ -12,8 +12,7 @@ Every recipe ships a healthcheck. App services that depend on infra MUST gate st
|
|
|
12
12
|
| Memcached | `echo stats | nc -w 1 localhost 11211 \| grep -q uptime` | Memcached has no native ping; stats command is the cheapest readiness signal |
|
|
13
13
|
| RabbitMQ | `rabbitmq-diagnostics ping` | Built-in; takes ~30s to be ready, hence `start_period: 30s` |
|
|
14
14
|
| LocalStack | `curl -sf http://localhost:4566/_localstack/health \| grep -q running` | Internal endpoint reports per-service readiness |
|
|
15
|
-
|
|
|
16
|
-
| Mailpit | `wget --spider http://localhost:8025` | Same |
|
|
15
|
+
| Mailpit | `wget --spider http://localhost:8025` | UI port responds when SMTP is also ready |
|
|
17
16
|
| smtp4dev | `wget --spider http://localhost:80` | UI on internal port 80 |
|
|
18
17
|
| MinIO | `curl -f http://localhost:9000/minio/health/live` | Documented liveness endpoint |
|
|
19
18
|
| Meilisearch | `curl -f http://localhost:7700/health` | Documented |
|
|
@@ -41,11 +40,11 @@ api:
|
|
|
41
40
|
condition: service_healthy # waits for the healthcheck to pass
|
|
42
41
|
redis:
|
|
43
42
|
condition: service_healthy
|
|
44
|
-
|
|
45
|
-
condition:
|
|
43
|
+
mailpit:
|
|
44
|
+
condition: service_healthy
|
|
46
45
|
```
|
|
47
46
|
|
|
48
|
-
`service_healthy` is the strictest gate — no traffic until the healthcheck has passed at least once. Use it for
|
|
47
|
+
`service_healthy` is the strictest gate — no traffic until the healthcheck has passed at least once. Use it for every dependency that declares a healthcheck, including Mailpit. Use `service_started` only when a dependency has no healthcheck to gate on.
|
|
49
48
|
|
|
50
49
|
## Common mistakes
|
|
51
50
|
|