@brunosps00/dev-workflow 1.7.0 → 1.7.1
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 +1 -1
- package/README.md +1 -1
- package/lib/install-deps.js +15 -0
- package/lib/install-open-design.js +39 -0
- package/lib/utils.js +46 -6
- package/package.json +2 -2
- package/scaffold/en/commands/dw-new-project.md +24 -21
- package/scaffold/en/templates/project-onepager.md +12 -11
- package/scaffold/pt-br/commands/dw-new-project.md +24 -21
- package/scaffold/pt-br/templates/project-onepager.md +12 -11
- package/scaffold/skills/docker-compose-recipes/SKILL.md +6 -5
- package/scaffold/skills/docker-compose-recipes/references/compose-composition.md +7 -7
- package/scaffold/skills/docker-compose-recipes/references/env-conventions.md +3 -1
- package/scaffold/skills/docker-compose-recipes/references/healthcheck-patterns.md +4 -4
- package/scaffold/skills/docker-compose-recipes/services/mailpit.yml +4 -4
- package/scaffold/skills/docker-compose-recipes/services/postgres-pgvector.yml +31 -0
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ Use these when you want step-by-step control instead of `/dw-autopilot`.
|
|
|
81
81
|
| **`/dw-harness-audit`** | Deterministic health scorecard for the dev-workflow install, agents, wrappers, MCPs, and gates. |
|
|
82
82
|
| **`/dw-skill-health`** | Audits installed skills and agents for bloat, duplication, and missing references. |
|
|
83
83
|
| **`/dw-learn`** | Synthesizes durable decisions (confidence-tagged), bugfixes, deviations, and git history into atomic confidence-weighted **instincts** you approve at `.dw/memory/instincts/`; can propose constitution principles. On-demand and human-in-the-loop — **no always-on observer**. |
|
|
84
|
-
| **`/dw-new-project`** | Bootstrap a new project from empty directory. Stack interview, wraps official `create-*` tools
|
|
84
|
+
| **`/dw-new-project`** | Bootstrap a new project from an empty or docs-first directory while preserving existing documentation and prototypes. Stack interview includes Next.js + NestJS, Postgres + pgvector, pg-boss, Mailpit, dev topology, and wraps official `create-*` tools before composing dev infrastructure, `.env`, scripts, CI, and `.dw/rules/`. |
|
|
85
85
|
| **`/dw-dockerize`** | Reads existing project, detects stack + runtime deps, proposes Dockerfile + docker-compose for dev/prod with explicit trade-offs (Conservative/Balanced/Bold). |
|
|
86
86
|
| **`/dw-install-azure-skills`** | **Opt-in.** Clones curated Azure skills from [`MicrosoftDocs/Agent-Skills`](https://github.com/MicrosoftDocs/Agent-Skills) (CC-BY-4.0) into `.agents/skills/azure/` and registers the [Microsoft Learn MCP Server](https://learn.microsoft.com/en-us/training/support/mcp-get-started) (HTTP, no-auth). Interactive category selection (Compute / Data & Storage / AI & ML / Networking / Identity & Security / DevOps / Observability / Integration / Architecture / All). Re-run to refresh from upstream. Also available as CLI: `npx @brunosps00/dev-workflow install-azure-skills`. |
|
|
87
87
|
| **`/dw-install-aws-skills`** | **Opt-in.** Clones curated AWS skills from [`aws/agent-toolkit-for-aws`](https://github.com/aws/agent-toolkit-for-aws) (Apache 2.0) into `.agents/skills/aws/` and registers the unified [AWS MCP Server](https://docs.aws.amazon.com/aws-mcp/) (stdio via `uvx mcp-proxy-for-aws@latest`). **Requires `uv`, `aws cli ≥ 2.32.0`, and AWS credentials.** Interactive category selection (Core / Analytics / Database / EC2 / Migration / Networking / Operations / Security / Serverless / Storage / All). The agent gains `aws___call_aws` (executes 15,000+ AWS APIs) and `aws___run_script` (Python sandboxed) — review `.dw/references/aws-mcp-instructions.md` for the destructive-operations protocol. Also available as CLI: `npx @brunosps00/dev-workflow install-aws-skills [--region=<aws-region>]`. |
|
package/lib/install-deps.js
CHANGED
|
@@ -90,6 +90,7 @@ function run() {
|
|
|
90
90
|
check: openDesign.check,
|
|
91
91
|
install: openDesign.install,
|
|
92
92
|
instructions: openDesign.instructions(),
|
|
93
|
+
sync: openDesign.syncProjectAssets,
|
|
93
94
|
},
|
|
94
95
|
];
|
|
95
96
|
|
|
@@ -122,6 +123,7 @@ function run() {
|
|
|
122
123
|
try {
|
|
123
124
|
if (typeof dep.check === 'function' && dep.check()) {
|
|
124
125
|
console.log(' \x1b[32m✓ already installed\x1b[0m');
|
|
126
|
+
runDepSync(dep);
|
|
125
127
|
installed++;
|
|
126
128
|
continue;
|
|
127
129
|
}
|
|
@@ -131,6 +133,7 @@ function run() {
|
|
|
131
133
|
execSync(dep.install, { stdio: 'pipe', timeout: 300000 });
|
|
132
134
|
}
|
|
133
135
|
console.log(' \x1b[32m✓\x1b[0m');
|
|
136
|
+
runDepSync(dep);
|
|
134
137
|
installed++;
|
|
135
138
|
} catch (err) {
|
|
136
139
|
console.log(' \x1b[31m✗\x1b[0m');
|
|
@@ -202,3 +205,15 @@ function printBrowserGuidance() {
|
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
module.exports = { run };
|
|
208
|
+
|
|
209
|
+
function runDepSync(dep) {
|
|
210
|
+
if (typeof dep.sync !== 'function') return;
|
|
211
|
+
try {
|
|
212
|
+
const result = dep.sync();
|
|
213
|
+
if (result && result.synced === false && result.reason) {
|
|
214
|
+
console.log(` (project assets not synced: ${result.reason})`);
|
|
215
|
+
}
|
|
216
|
+
} catch (err) {
|
|
217
|
+
console.log(` (project asset sync failed: ${err.message})`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -2,6 +2,12 @@ const fs = require('fs');
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { execFileSync } = require('child_process');
|
|
5
|
+
const { COMMANDS } = require('./constants');
|
|
6
|
+
const { copyDir, writeFile, log } = require('./utils');
|
|
7
|
+
const { generateWrappers } = require('./wrappers');
|
|
8
|
+
const { readInstallState } = require('./install-state');
|
|
9
|
+
|
|
10
|
+
const SCAFFOLD_DIR = path.join(__dirname, '..', 'scaffold');
|
|
5
11
|
|
|
6
12
|
const OPEN_DESIGN_REPO = 'https://github.com/nexu-io/open-design';
|
|
7
13
|
const OPEN_DESIGN_REF = '1cb7eae';
|
|
@@ -35,6 +41,38 @@ function install() {
|
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Sync the dw-open-design command, scripts and harness wrappers into the
|
|
46
|
+
* current project. install-deps provisions the od CLI, but the skill lives in
|
|
47
|
+
* the project scaffold — without this, users only get the command after a
|
|
48
|
+
* manual `dev-workflow update` (the exact gap reported in the field).
|
|
49
|
+
*/
|
|
50
|
+
function syncProjectAssets(projectRoot = process.cwd()) {
|
|
51
|
+
const state = readInstallState(projectRoot);
|
|
52
|
+
if (!state) {
|
|
53
|
+
return { synced: false, reason: 'no dev-workflow install found in this project (run init/update first)' };
|
|
54
|
+
}
|
|
55
|
+
const lang = state.lang && COMMANDS[state.lang] ? state.lang : 'en';
|
|
56
|
+
const cmd = COMMANDS[lang].find((entry) => entry.name === 'dw-open-design')
|
|
57
|
+
|| COMMANDS.en.find((entry) => entry.name === 'dw-open-design');
|
|
58
|
+
if (!cmd) {
|
|
59
|
+
return { synced: false, reason: 'dw-open-design missing from command registry' };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const commandSrc = path.join(SCAFFOLD_DIR, lang, 'commands', 'dw-open-design.md');
|
|
63
|
+
const commandDest = path.join(projectRoot, '.dw', 'commands', 'dw-open-design.md');
|
|
64
|
+
const status = writeFile(commandDest, fs.readFileSync(commandSrc, 'utf-8'), true);
|
|
65
|
+
log(status, commandDest);
|
|
66
|
+
|
|
67
|
+
const scriptsSrc = path.join(SCAFFOLD_DIR, 'scripts', 'open-design');
|
|
68
|
+
if (fs.existsSync(scriptsSrc)) {
|
|
69
|
+
copyDir(scriptsSrc, path.join(projectRoot, '.dw', 'scripts', 'open-design'), true);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
generateWrappers(projectRoot, [cmd], true);
|
|
73
|
+
return { synced: true };
|
|
74
|
+
}
|
|
75
|
+
|
|
38
76
|
function instructions() {
|
|
39
77
|
return [
|
|
40
78
|
'Open Design CLI is provisioned by dev-workflow into a managed checkout:',
|
|
@@ -80,6 +118,7 @@ function isAtLeast(actual, minimum) {
|
|
|
80
118
|
}
|
|
81
119
|
|
|
82
120
|
module.exports = {
|
|
121
|
+
syncProjectAssets,
|
|
83
122
|
OPEN_DESIGN_REF,
|
|
84
123
|
OPEN_DESIGN_VENDOR_DIR,
|
|
85
124
|
check,
|
package/lib/utils.js
CHANGED
|
@@ -90,6 +90,20 @@ function writeJson(filePath, value) {
|
|
|
90
90
|
fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\n', 'utf-8');
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
function findStandaloneMarkers(content, marker) {
|
|
94
|
+
// Marker names also appear in explanatory prose, so only a full marker line delimits a block.
|
|
95
|
+
const escapedMarker = marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
96
|
+
const pattern = new RegExp(`^[\\t ]*${escapedMarker}[\\t ]*\\r?$`, 'gm');
|
|
97
|
+
const markers = [];
|
|
98
|
+
let match;
|
|
99
|
+
|
|
100
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
101
|
+
const start = match.index + match[0].indexOf(marker);
|
|
102
|
+
markers.push({ start, end: start + marker.length });
|
|
103
|
+
}
|
|
104
|
+
return markers;
|
|
105
|
+
}
|
|
106
|
+
|
|
93
107
|
/**
|
|
94
108
|
* Upsert a delimited block inside an existing file.
|
|
95
109
|
*
|
|
@@ -105,8 +119,19 @@ function upsertDelimitedBlock(filePath, blockContent, startMarker, endMarker) {
|
|
|
105
119
|
|
|
106
120
|
// The block content already includes its own start/end markers (so the scaffold
|
|
107
121
|
// file can be read verbatim). Validate that.
|
|
108
|
-
|
|
109
|
-
|
|
122
|
+
const blockStarts = findStandaloneMarkers(blockContent, startMarker);
|
|
123
|
+
const blockEnds = findStandaloneMarkers(blockContent, endMarker);
|
|
124
|
+
if (blockStarts.length === 0 || blockEnds.length === 0) {
|
|
125
|
+
throw new Error(`Block content for ${filePath} is missing standalone markers`);
|
|
126
|
+
}
|
|
127
|
+
if (blockStarts.length > 1 || blockEnds.length > 1) {
|
|
128
|
+
throw new Error(`Block content for ${filePath} has duplicate standalone markers`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const blockStart = blockStarts[0];
|
|
132
|
+
const blockEnd = blockEnds[0];
|
|
133
|
+
if (blockEnd.start < blockStart.end) {
|
|
134
|
+
throw new Error(`Block content for ${filePath} is missing standalone markers`);
|
|
110
135
|
}
|
|
111
136
|
|
|
112
137
|
if (!exists) {
|
|
@@ -115,17 +140,32 @@ function upsertDelimitedBlock(filePath, blockContent, startMarker, endMarker) {
|
|
|
115
140
|
}
|
|
116
141
|
|
|
117
142
|
const current = fs.readFileSync(filePath, 'utf-8');
|
|
118
|
-
const
|
|
143
|
+
const currentStarts = findStandaloneMarkers(current, startMarker);
|
|
144
|
+
const currentEnds = findStandaloneMarkers(current, endMarker);
|
|
119
145
|
|
|
120
|
-
if (
|
|
146
|
+
if (currentStarts.length === 0 && currentEnds.length === 0) {
|
|
121
147
|
const separator = current.endsWith('\n') ? '\n' : '\n\n';
|
|
122
148
|
const next = current + separator + (blockContent.endsWith('\n') ? blockContent : blockContent + '\n');
|
|
123
149
|
fs.writeFileSync(filePath, next, 'utf-8');
|
|
124
150
|
return 'updated';
|
|
125
151
|
}
|
|
126
152
|
|
|
127
|
-
|
|
128
|
-
|
|
153
|
+
if (currentStarts.length > 1 || currentEnds.length > 1) {
|
|
154
|
+
throw new Error(`Existing file ${filePath} has duplicate standalone markers`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (currentStarts.length !== 1 || currentEnds.length !== 1) {
|
|
158
|
+
throw new Error(`Existing file ${filePath} has unbalanced standalone markers`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const currentStart = currentStarts[0];
|
|
162
|
+
const currentEnd = currentEnds[0];
|
|
163
|
+
if (currentEnd.start < currentStart.end) {
|
|
164
|
+
throw new Error(`Existing file ${filePath} has unbalanced standalone markers`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const before = current.slice(0, currentStart.start);
|
|
168
|
+
const after = current.slice(currentEnd.end);
|
|
129
169
|
const next = before + blockContent.trim() + after;
|
|
130
170
|
if (next === current) return 'unchanged';
|
|
131
171
|
fs.writeFileSync(filePath, next, 'utf-8');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brunosps00/dev-workflow",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "AI-driven development workflow commands for any project. Scaffolds a complete PRD-to-PR pipeline with multi-platform AI assistant support.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"dev-workflow": "./bin/dev-workflow.js"
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"repository": {
|
|
44
44
|
"type": "git",
|
|
45
|
-
"url": "https://github.com/
|
|
45
|
+
"url": "https://github.com/brunosps/dev-workflow"
|
|
46
46
|
},
|
|
47
47
|
"author": "Bruno Santos"
|
|
48
48
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<system_instructions>
|
|
2
|
-
You are a workspace bootstrap lead for the dev-workflow ecosystem. Your job is to take an empty
|
|
2
|
+
You are a workspace bootstrap lead for the dev-workflow ecosystem. Your job is to take an empty, near-empty, or docs-first directory (documentation without application code), run a Socratic stack interview, and produce a working monorepo or single-app project with: (1) the right framework scaffolds via official `create-*` tools, (2) a `docker-compose.dev.yml` covering every selected dev dependency (db, cache, queue, email, storage, search, observability, proxy), (3) `.env.example`, scripts, `.gitignore`, `.dockerignore`, GitHub Action, README, and (4) a seeded `.dw/rules/index.md`.
|
|
3
3
|
|
|
4
4
|
<critical>This command MUST run AFTER `npx dev-workflow init` has populated `.dw/`. If `.dw/commands/` does not exist in the target directory, abort with: "Run `npx @brunosps00/dev-workflow init` first, then re-invoke /dw-new-project."</critical>
|
|
5
5
|
<critical>NEVER touch files outside the new project's directory. The interview captures `{{TARGET_DIR}}`; all writes are scoped under it.</critical>
|
|
6
6
|
<critical>Phase 3 (execution) runs ONLY after the user explicitly approves the plan presented in Phase 2. No flag bypass.</critical>
|
|
7
|
-
<critical>
|
|
7
|
+
<critical>Mailpit is the DEFAULT for email-in-dev. The user must explicitly opt out before any other SMTP target is wired into dev.</critical>
|
|
8
8
|
|
|
9
9
|
## When to Use
|
|
10
10
|
|
|
11
|
-
- Starting a new project from an empty directory and you want the dev-workflow conventions, containerized infra, and CI scaffolding from day one
|
|
11
|
+
- Starting a new project from an empty or docs-first directory and you want the dev-workflow conventions, containerized infra, and CI scaffolding from day one
|
|
12
12
|
- Replacing manual `pnpm create next-app && create vite ...` ceremony with a guided interview that captures the full dev environment
|
|
13
13
|
- Spinning up a learning sandbox where you want a realistic stack (db + cache + email + observability) without 30 minutes of YAML
|
|
14
|
-
- NOT for adding services to
|
|
14
|
+
- NOT for adding services to a project that already has manifests or application code — use `/dw-dockerize --audit`
|
|
15
15
|
- NOT for adding a new app inside an existing monorepo — that needs a different command (planned for a future release)
|
|
16
16
|
- NOT a replacement for `/dw-plan prd` — this generates the workspace, not the product spec
|
|
17
17
|
|
|
@@ -52,7 +52,7 @@ Execute phases in order. Phase 3 runs ONLY after user approval at the end of Pha
|
|
|
52
52
|
1. Verify `.dw/commands/` exists in `{{TARGET_DIR}}`. If not, abort with the message above.
|
|
53
53
|
2. Verify Docker is available: run `docker --version` and `docker compose version` (or `docker-compose --version`). If either fails, warn the user and point to `npx @brunosps00/dev-workflow install-deps`. Do NOT abort — the user may want a `--dry-run` plan even without Docker.
|
|
54
54
|
3. Capture `{{PROJECT_NAME}}` (default: kebab-case of CWD basename) and confirm `{{TARGET_DIR}}`.
|
|
55
|
-
4.
|
|
55
|
+
4. Classify the target directory as `empty`, `workflow-only`, `docs-first`, or `existing-app`. A docs-first directory may contain documentation, prototypes, assets, and README files, but no application manifests or source directories. List every path that will be preserved and ask for confirmation. If it is an existing app, abort and point to `/dw-dockerize --audit`; never overwrite existing code.
|
|
56
56
|
|
|
57
57
|
Emit a VERIFICATION REPORT for Phase 0 (Docker version captured, target dir state).
|
|
58
58
|
|
|
@@ -68,21 +68,21 @@ Use `AskUserQuestion` when available; otherwise plain numbered prompts. Ask in *
|
|
|
68
68
|
2. **Language(s)**: TypeScript/JavaScript, Python, C#, Rust (per app)
|
|
69
69
|
3. **Framework per layer** (curated list — refuse anything outside):
|
|
70
70
|
- **Frontend**: Next.js (app router), Vite + React (TS template)
|
|
71
|
-
- **Backend**: FastAPI (Python), ASP.NET Core minimal API (C#), Axum (Rust)
|
|
72
|
-
- **Fullstack
|
|
71
|
+
- **Backend**: NestJS or Fastify (Node TS), FastAPI (Python), ASP.NET Core minimal API (C#), Axum (Rust)
|
|
72
|
+
- **Fullstack**: T3 stack (single bundle), Next.js + NestJS, or Next.js + FastAPI (separate apps in a monorepo)
|
|
73
73
|
4. **Package manager** (NO default — ask explicitly):
|
|
74
74
|
- For Node: npm / pnpm / yarn
|
|
75
75
|
- For Python: poetry / uv / pip + venv
|
|
76
76
|
- For .NET: dotnet (built-in)
|
|
77
77
|
- For Rust: cargo (built-in)
|
|
78
|
-
5. **If fullstack** —
|
|
78
|
+
5. **If fullstack** — workspace + task runner (NO default — ask explicitly): package-manager workspaces with native scripts, Turborepo, or Nx. Record combinations such as `pnpm workspaces + Turborepo`.
|
|
79
79
|
|
|
80
80
|
#### Layer B — Infra (only ask what fits the shape)
|
|
81
81
|
|
|
82
|
-
6. **Database**: Postgres / MySQL / SQLite (file, no service) / MongoDB (out of scope for compose recipes — note and skip if chosen) / none
|
|
82
|
+
6. **Database**: Postgres / Postgres + pgvector / MySQL / SQLite (file, no service) / MongoDB (out of scope for compose recipes — note and skip if chosen) / none. For Postgres + pgvector, select an explicit supported recipe/version.
|
|
83
83
|
7. **Cache**: Redis / Memcached / none
|
|
84
|
-
8. **Queue / message broker**: BullMQ (Node
|
|
85
|
-
9. **Email — dev capture** (default: **
|
|
84
|
+
8. **Queue / message broker**: pg-boss (Node + Postgres, no extra service), BullMQ (Node + Redis), Celery (Python only), RabbitMQ (any), LocalStack SQS (any), none. If chosen, also ask whether the project will have async workers.
|
|
85
|
+
9. **Email — dev capture** (default: **Mailpit**, ask only if user wants to override): Mailpit / MailHog / smtp4dev / skip
|
|
86
86
|
10. **Email — prod target** (only ask if user wants email at all): SMTP relay / SendGrid / Resend / Postmark / SES / skip
|
|
87
87
|
11. **Object storage**: S3 (real, no service in compose) / MinIO (dev) / GCS (no service) / none
|
|
88
88
|
12. **Search**: Meilisearch / Typesense / Elasticsearch / none
|
|
@@ -93,7 +93,8 @@ Use `AskUserQuestion` when available; otherwise plain numbered prompts. Ask in *
|
|
|
93
93
|
#### Layer C — Tooling
|
|
94
94
|
|
|
95
95
|
16. **Auth** (only ask if applicable to chosen stack):
|
|
96
|
-
- Next.js:
|
|
96
|
+
- Next.js: Auth.js / generic OIDC / Clerk / custom JWT / none
|
|
97
|
+
- NestJS: generic OIDC / Passport JWT / custom auth / none
|
|
97
98
|
- FastAPI: fastapi-users / authlib / custom JWT / none
|
|
98
99
|
- ASP.NET: built-in Identity / IdentityServer / custom JWT / none
|
|
99
100
|
- Axum: tower-cookies + jsonwebtoken / custom / none
|
|
@@ -102,7 +103,8 @@ Use `AskUserQuestion` when available; otherwise plain numbered prompts. Ask in *
|
|
|
102
103
|
- Python: Ruff + Black / Ruff only
|
|
103
104
|
- C#: dotnet format
|
|
104
105
|
- Rust: rustfmt + clippy (default)
|
|
105
|
-
18. **
|
|
106
|
+
18. **Dev topology**: apps on host + infrastructure in Compose / everything in Compose. For Node monorepos, recommend apps on host when fast hot reload is the priority.
|
|
107
|
+
19. **CI**: GitHub Actions (always seed; user can opt out)
|
|
106
108
|
|
|
107
109
|
Save all answers in memory for Phase 2.
|
|
108
110
|
|
|
@@ -133,6 +135,7 @@ Run in this order. Each step emits its own 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>` then trim interactive prompts; if no non-interactive flag works, generate the structure inline (`src/server.ts` + `src/routes/` + `package.json`) |
|
|
137
140
|
| FastAPI | NO official `create-*`. Generate inline: `pyproject.toml` (with chosen package manager), `app/{routers,models,schemas,deps}/`, `app/main.py`, `tests/` skeleton |
|
|
138
141
|
| ASP.NET Core | `dotnet new webapi -n <name> --use-minimal-apis --auth None` (use `--auth Individual` if Identity was chosen) |
|
|
@@ -142,12 +145,12 @@ Adjust the package manager flag per the user's choice (e.g., `--use-npm`, `--use
|
|
|
142
145
|
|
|
143
146
|
For **fullstack-T3**: that's it for app code (T3 ships everything in one tree).
|
|
144
147
|
|
|
145
|
-
For **fullstack-NextJS+FastAPI**:
|
|
148
|
+
For **fullstack-NextJS+NestJS** or **fullstack-NextJS+FastAPI**: scaffold directly into `apps/web/` and `apps/api/` without moving or deleting pre-existing documentation.
|
|
146
149
|
|
|
147
150
|
#### 3.2 Compose monorepo (fullstack only)
|
|
148
151
|
|
|
149
152
|
If fullstack:
|
|
150
|
-
1.
|
|
153
|
+
1. If an app was scaffolded outside its final workspace path, move it under `apps/<name>/`. Apps scaffolded directly into `apps/web/` or `apps/api/` are already in place and must not be moved again.
|
|
151
154
|
2. Create `pnpm-workspace.yaml` (or equivalent), root `package.json` with workspace scripts, root `tsconfig.base.json` if shared TS config.
|
|
152
155
|
3. If user picked Turborepo: add `turbo.json` with `dev`, `build`, `lint`, `test` pipelines.
|
|
153
156
|
4. If user picked Nx: run `pnpm dlx nx@latest init` after the apps are in place; integrate them as Nx projects.
|
|
@@ -159,7 +162,7 @@ If fullstack:
|
|
|
159
162
|
- Concatenate selected service blocks under `services:`.
|
|
160
163
|
- Aggregate named volumes under `volumes:`.
|
|
161
164
|
- Resolve port collisions if any.
|
|
162
|
-
-
|
|
165
|
+
- For `everything in Compose`, add the app service(s) at the end (build context = `apps/<name>` or root, Dockerfile.dev, env_file, volumes, depends_on with `condition: service_healthy`). For `apps on host`, compose infrastructure only and use `localhost` endpoints in app-facing environment variables.
|
|
163
166
|
3. Add a header comment: `# Generated by /dw-new-project on YYYY-MM-DD`.
|
|
164
167
|
|
|
165
168
|
#### 3.4 Generate `.env.example`
|
|
@@ -214,7 +217,7 @@ Minimal scaffold:
|
|
|
214
217
|
| Database | <db or n/a> |
|
|
215
218
|
| Cache | <cache or n/a> |
|
|
216
219
|
| Queue | <queue or n/a> |
|
|
217
|
-
| Email (dev) | <mailhog|
|
|
220
|
+
| Email (dev) | <mailpit|mailhog|smtp4dev|none> |
|
|
218
221
|
| Search | <search or n/a> |
|
|
219
222
|
| Observability | <observability or n/a> |
|
|
220
223
|
| Reverse proxy | <traefik|none> |
|
|
@@ -230,7 +233,7 @@ Minimal scaffold:
|
|
|
230
233
|
## Conventions
|
|
231
234
|
|
|
232
235
|
- See `.dw/rules/<module>.md` after `/dw-analyze-project` runs.
|
|
233
|
-
- Email-in-dev uses
|
|
236
|
+
- Email-in-dev uses Mailpit by default; the app NEVER sends real mail in dev.
|
|
234
237
|
- All env vars live in `.env` (gitignored); `.env.example` is the template.
|
|
235
238
|
```
|
|
236
239
|
|
|
@@ -273,7 +276,7 @@ date: YYYY-MM-DD
|
|
|
273
276
|
shape: <frontend|backend|fullstack>
|
|
274
277
|
languages: [typescript, python, ...]
|
|
275
278
|
frameworks: { web: '...', api: '...' }
|
|
276
|
-
services: [postgres,
|
|
279
|
+
services: [postgres-pgvector, mailpit, minio, ...]
|
|
277
280
|
package_manager: <pnpm|npm|yarn|poetry|uv|cargo|dotnet>
|
|
278
281
|
monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
279
282
|
---
|
|
@@ -302,7 +305,7 @@ monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
|
302
305
|
1. `cp .env.example .env` and review credentials.
|
|
303
306
|
2. `pnpm install` (or your chosen package manager).
|
|
304
307
|
3. `pnpm dev:up` to bring up all services. Wait for healthchecks.
|
|
305
|
-
4. Open
|
|
308
|
+
4. Open Mailpit UI at http://localhost:8025 to confirm email capture is wired.
|
|
306
309
|
5. `/dw-plan prd` to draft the first feature.
|
|
307
310
|
6. After your first substantial commit, run `/dw-analyze-project` to enrich `.dw/rules/`.
|
|
308
311
|
```
|
|
@@ -332,7 +335,7 @@ monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
|
332
335
|
- User picks MongoDB → note "MongoDB recipe not bundled in v0.8.0; we'll add app dependencies but you'll need to wire the service manually". Continue.
|
|
333
336
|
- User picks Caddy → same: note as not in bundled recipes; continue without compose service.
|
|
334
337
|
- Port already bound on host → suggest the override env var and continue; do not pick a different port silently.
|
|
335
|
-
-
|
|
338
|
+
- Docs-first working tree → preserve every listed path and write only to approved new paths. Existing app → abort and point to `/dw-dockerize --audit`.
|
|
336
339
|
|
|
337
340
|
## Integration With Other dw-* Commands
|
|
338
341
|
|
|
@@ -23,20 +23,21 @@ services: []
|
|
|
23
23
|
|-------|--------|-----------|
|
|
24
24
|
| Shape | frontend / backend / fullstack | [why this shape — single product surface, API for partners, etc.] |
|
|
25
25
|
| Frontend | Next.js / Vite+React / n/a | [why this framework — SSR needs, SPA simplicity, etc.] |
|
|
26
|
-
| Backend | FastAPI / ASP.NET Core minimal / Axum /
|
|
27
|
-
| Database | Postgres / MySQL / SQLite / MongoDB / none | [why this DB — relational
|
|
26
|
+
| Backend | NestJS / Fastify / FastAPI / ASP.NET Core minimal / Axum / n/a | [why this framework — team expertise, ecosystem, latency targets] |
|
|
27
|
+
| Database | Postgres / Postgres+pgvector / MySQL / SQLite / MongoDB / none | [why this DB — relational, vector, transactional needs, etc.] |
|
|
28
28
|
| Cache | Redis / Memcached / none | [why or why not] |
|
|
29
|
-
| Queue | BullMQ / Celery / RabbitMQ / LocalStack SQS / none | [why or why not + sync vs async workers] |
|
|
30
|
-
| Email — dev |
|
|
29
|
+
| Queue | pg-boss / BullMQ / Celery / RabbitMQ / LocalStack SQS / none | [why or why not + sync vs async workers] |
|
|
30
|
+
| Email — dev | Mailpit (default) / MailHog / smtp4dev / none | [usually Mailpit — capture only, never sends real mail] |
|
|
31
31
|
| Email — prod | SMTP / SendGrid / Resend / Postmark / SES / none | [why this provider — volume, deliverability, cost] |
|
|
32
32
|
| Object storage | S3 / MinIO (dev) / GCS / none | [why or why not] |
|
|
33
33
|
| Search | Meilisearch / Typesense / Elasticsearch / none | [why this engine — features, scale, simplicity] |
|
|
34
34
|
| Observability | Sentry / OTel + Jaeger / none | [why this approach — error tracking only, full tracing, etc.] |
|
|
35
35
|
| Reverse proxy | Traefik / Caddy / none | [usually only needed for multi-host dev or prod] |
|
|
36
|
-
| Auth |
|
|
36
|
+
| Auth | Auth.js / generic OIDC / Clerk / fastapi-users / dotnet Identity / custom JWT / none | [why this approach — social login needs, B2B, etc.] |
|
|
37
37
|
| Linter / formatter | Biome / ESLint+Prettier / Ruff+Black / dotnet format / cargo fmt+clippy | [team preference] |
|
|
38
38
|
| Package manager | pnpm / npm / yarn / poetry / uv / cargo / dotnet | [team preference] |
|
|
39
|
-
|
|
|
39
|
+
| Workspace + task runner | pnpm workspaces + Turborepo / npm workspaces / Nx / n/a | [only for fullstack — caching/build needs] |
|
|
40
|
+
| Dev topology | apps on host / everything in Compose | [hot reload versus environment parity] |
|
|
40
41
|
| CI | GitHub Actions / none | [usually GitHub Actions; opt out only for non-public repos] |
|
|
41
42
|
|
|
42
43
|
## Services & Infra
|
|
@@ -47,7 +48,7 @@ services: []
|
|
|
47
48
|
|---------|-------------|----|--------------------|
|
|
48
49
|
| postgres | 5432 | — | POSTGRES_USER=app, POSTGRES_PASSWORD=app, POSTGRES_DB=app |
|
|
49
50
|
| redis | 6379 | — | (no auth in dev) |
|
|
50
|
-
|
|
|
51
|
+
| mailpit | 1025 (smtp), 8025 (UI) | http://localhost:8025 | (no auth) |
|
|
51
52
|
| ... | ... | ... | ... |
|
|
52
53
|
|
|
53
54
|
## Architecture Diagram
|
|
@@ -59,12 +60,12 @@ services: []
|
|
|
59
60
|
[ Browser ] -> [ Next.js (apps/web) ]
|
|
60
61
|
|
|
61
62
|
# Fullstack
|
|
62
|
-
[ Browser ] -> [ Next.js (apps/web) ] -> [
|
|
63
|
+
[ Browser ] -> [ Next.js (apps/web) ] -> [ NestJS (apps/api) ] -> [ Postgres ]
|
|
63
64
|
|-> [ Redis ]
|
|
64
|
-
|-> [
|
|
65
|
+
|-> [ Mailpit ]
|
|
65
66
|
|
|
66
67
|
# With observability
|
|
67
|
-
... -> [
|
|
68
|
+
... -> [ NestJS ] -> { OTLP } -> [ Jaeger ]
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
## Generated Files
|
|
@@ -75,7 +76,7 @@ services: []
|
|
|
75
76
|
{{TARGET_DIR}}/
|
|
76
77
|
├── apps/
|
|
77
78
|
│ ├── web/ (created by `pnpm create next-app`)
|
|
78
|
-
│ └── api/ (
|
|
79
|
+
│ └── api/ (created by `pnpm dlx @nestjs/cli` or selected scaffold)
|
|
79
80
|
├── packages/
|
|
80
81
|
│ └── shared/ (created by /dw-new-project)
|
|
81
82
|
├── docker-compose.dev.yml (composed from .agents/skills/docker-compose-recipes/)
|
|
@@ -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 / Postgres + pgvector / MySQL / SQLite (arquivo, sem service) / MongoDB (fora do escopo dos compose recipes — anote e siga sem service se escolhido) / nenhum. Para Postgres + pgvector, selecione explicitamente a recipe/version suportada.
|
|
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 / MailHog / 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
|
|
|
@@ -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,7 +162,7 @@ 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.
|
|
163
166
|
3. Adicione header: `# Generated by /dw-new-project on YYYY-MM-DD`.
|
|
164
167
|
|
|
165
168
|
#### 3.4 Gerar `.env.example`
|
|
@@ -214,7 +217,7 @@ Scaffold minimo:
|
|
|
214
217
|
| Database | <db ou n/a> |
|
|
215
218
|
| Cache | <cache ou n/a> |
|
|
216
219
|
| Fila | <fila ou n/a> |
|
|
217
|
-
| Email (dev) | <mailhog|
|
|
220
|
+
| Email (dev) | <mailpit|mailhog|smtp4dev|nenhum> |
|
|
218
221
|
| Search | <search ou n/a> |
|
|
219
222
|
| Observability | <observability ou n/a> |
|
|
220
223
|
| Reverse proxy | <traefik|nenhum> |
|
|
@@ -230,7 +233,7 @@ Scaffold minimo:
|
|
|
230
233
|
## Convencoes
|
|
231
234
|
|
|
232
235
|
- Veja `.dw/rules/<modulo>.md` apos o `/dw-analyze-project` rodar.
|
|
233
|
-
- Email em dev usa
|
|
236
|
+
- Email em dev usa Mailpit por default; o app NUNCA envia email real em dev.
|
|
234
237
|
- Toda env var vive em `.env` (gitignored); `.env.example` e o template.
|
|
235
238
|
```
|
|
236
239
|
|
|
@@ -273,7 +276,7 @@ date: YYYY-MM-DD
|
|
|
273
276
|
shape: <frontend|backend|fullstack>
|
|
274
277
|
languages: [typescript, python, ...]
|
|
275
278
|
frameworks: { web: '...', api: '...' }
|
|
276
|
-
services: [postgres,
|
|
279
|
+
services: [postgres-pgvector, mailpit, minio, ...]
|
|
277
280
|
package_manager: <pnpm|npm|yarn|poetry|uv|cargo|dotnet>
|
|
278
281
|
monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
279
282
|
---
|
|
@@ -302,7 +305,7 @@ monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
|
302
305
|
1. `cp .env.example .env` e revise credenciais.
|
|
303
306
|
2. `pnpm install` (ou seu package manager).
|
|
304
307
|
3. `pnpm dev:up` para subir todos os servicos. Aguarde os healthchecks.
|
|
305
|
-
4. Abra a UI do
|
|
308
|
+
4. Abra a UI do Mailpit em http://localhost:8025 para confirmar a captura de email.
|
|
306
309
|
5. `/dw-plan prd` para a primeira feature.
|
|
307
310
|
6. Apos o primeiro commit substancial, rode `/dw-analyze-project` para enriquecer `.dw/rules/`.
|
|
308
311
|
```
|
|
@@ -332,7 +335,7 @@ monorepo: <pnpm-workspaces|turborepo|nx|none>
|
|
|
332
335
|
- 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
336
|
- Usuario escolhe Caddy → idem: anote como nao bundled; siga sem servico no compose.
|
|
334
337
|
- Porta ja ocupada no host → sugira a env var de override e siga; nao escolha outra porta em silencio.
|
|
335
|
-
- Working tree
|
|
338
|
+
- Working tree docs-first → preserve cada path listado e escreva apenas nos novos paths aprovados. Existing app → aborte e indique `/dw-dockerize --audit`.
|
|
336
339
|
|
|
337
340
|
## Integracao com Outros dw-* Commands
|
|
338
341
|
|
|
@@ -23,20 +23,21 @@ 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 / Postgres+pgvector / MySQL / SQLite / MongoDB / nenhum | [por que esse DB — relacional, vetorial, transacional, etc.] |
|
|
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) / MailHog / 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
|
|
@@ -47,7 +48,7 @@ services: []
|
|
|
47
48
|
|---------|--------------|----|--------------------|
|
|
48
49
|
| postgres | 5432 | — | POSTGRES_USER=app, POSTGRES_PASSWORD=app, 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
|
|
|
53
54
|
## Diagrama da Arquitetura
|
|
@@ -59,12 +60,12 @@ services: []
|
|
|
59
60
|
[ Browser ] -> [ Next.js (apps/web) ]
|
|
60
61
|
|
|
61
62
|
# Fullstack
|
|
62
|
-
[ Browser ] -> [ Next.js (apps/web) ] -> [
|
|
63
|
+
[ Browser ] -> [ Next.js (apps/web) ] -> [ NestJS (apps/api) ] -> [ Postgres ]
|
|
63
64
|
|-> [ Redis ]
|
|
64
|
-
|-> [
|
|
65
|
+
|-> [ Mailpit ]
|
|
65
66
|
|
|
66
67
|
# Com observability
|
|
67
|
-
... -> [
|
|
68
|
+
... -> [ NestJS ] -> { OTLP } -> [ Jaeger ]
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
## Arquivos Gerados
|
|
@@ -75,7 +76,7 @@ services: []
|
|
|
75
76
|
{{TARGET_DIR}}/
|
|
76
77
|
├── apps/
|
|
77
78
|
│ ├── web/ (criado por `pnpm create next-app`)
|
|
78
|
-
│ └── api/ (
|
|
79
|
+
│ └── api/ (criado por `pnpm dlx @nestjs/cli` ou scaffold escolhido)
|
|
79
80
|
├── packages/
|
|
80
81
|
│ └── shared/ (criado pelo /dw-new-project)
|
|
81
82
|
├── docker-compose.dev.yml (composto a partir de .agents/skills/docker-compose-recipes/)
|
|
@@ -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, pgvector, 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
|
|
@@ -49,13 +49,14 @@ Each row points to `services/<name>.yml`.
|
|
|
49
49
|
| Service | Use | Default port(s) | Recipe |
|
|
50
50
|
|---------|-----|-----------------|--------|
|
|
51
51
|
| Postgres 16 (alpine) | Relational DB | `5432` | `services/postgres.yml` |
|
|
52
|
+
| PostgreSQL 18 + pgvector 0.8.2 | Relational + vector DB | `5432` | `services/postgres-pgvector.yml` |
|
|
52
53
|
| MySQL 8 | Relational DB | `3306` | `services/mysql.yml` |
|
|
53
54
|
| Redis 7 (alpine) | Cache, pub/sub, BullMQ backend | `6379` | `services/redis.yml` |
|
|
54
55
|
| Memcached 1.6 (alpine) | Cache | `11211` | `services/memcached.yml` |
|
|
55
56
|
| RabbitMQ 3 (management-alpine) | Message broker + UI | `5672`, UI `15672` | `services/rabbitmq.yml` |
|
|
56
57
|
| LocalStack | AWS-compatible local (S3, SQS, SNS, DynamoDB) | `4566` | `services/localstack.yml` |
|
|
57
|
-
|
|
|
58
|
-
|
|
|
58
|
+
| Mailpit | Default email-in-dev (capture only, never sends) | SMTP `1025`, UI `8025` | `services/mailpit.yml` |
|
|
59
|
+
| MailHog | Legacy email capture alternative | SMTP `1025`, UI `8025` | `services/mailhog.yml` |
|
|
59
60
|
| smtp4dev | Windows-friendly SMTP capture | SMTP `2525`, UI `5000` | `services/smtp4dev.yml` |
|
|
60
61
|
| MinIO | S3-compatible local | API `9000`, UI `9001` | `services/minio.yml` |
|
|
61
62
|
| Meilisearch | Search engine (lightweight) | `7700` | `services/meilisearch.yml` |
|
|
@@ -76,12 +77,12 @@ Each row points to `services/<name>.yml`.
|
|
|
76
77
|
- **Pin major.minor** in every `image:` line. Patch updates are safe; major bumps are deliberate.
|
|
77
78
|
- **Always include healthcheck**. No service is allowed to be opaque about readiness.
|
|
78
79
|
- **Default to dev**. Prod transforms are explicit (see `prod-vs-dev.md`).
|
|
79
|
-
- **Email-in-dev defaults to
|
|
80
|
+
- **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
81
|
- **Secrets never in the recipe**. Env vars reference `.env`; defaults in the recipe are OK only for non-secret config.
|
|
81
82
|
|
|
82
83
|
## Inspired by
|
|
83
84
|
|
|
84
|
-
Hand-curated by dev-workflow. Service defaults follow upstream documentation (Docker Hub `postgres`, `redis`, `
|
|
85
|
+
Hand-curated by dev-workflow. Service defaults follow upstream documentation (Docker Hub `postgres`, `pgvector/pgvector`, `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
86
|
|
|
86
87
|
## Structured Return
|
|
87
88
|
|
|
@@ -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-pgvector, 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
|
|
|
@@ -42,15 +42,15 @@ This file describes how `/dw-new-project` and `/dw-dockerize` merge the standalo
|
|
|
42
42
|
services:
|
|
43
43
|
# --- storage tier ---
|
|
44
44
|
postgres:
|
|
45
|
-
# ... contents from services/postgres.yml
|
|
45
|
+
# ... contents from services/postgres-pgvector.yml
|
|
46
46
|
|
|
47
47
|
# --- cache tier ---
|
|
48
48
|
redis:
|
|
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
|
|
|
@@ -23,7 +23,9 @@ POSTGRES_PORT=5432
|
|
|
23
23
|
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Compose performs variable substitution in `.env` references
|
|
26
|
+
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.
|
|
27
|
+
|
|
28
|
+
For the PostgreSQL + pgvector recipe, use the same connection variables. The image provides the extension binaries, but `CREATE EXTENSION IF NOT EXISTS vector` belongs in the application's reviewed migrations, not container startup scripts.
|
|
27
29
|
|
|
28
30
|
## What goes in `.env.example` vs `.env`
|
|
29
31
|
|
|
@@ -13,7 +13,7 @@ Every recipe ships a healthcheck. App services that depend on infra MUST gate st
|
|
|
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
15
|
| MailHog | `wget --spider http://localhost:8025` | UI port responds when SMTP is also ready |
|
|
16
|
-
| Mailpit | `wget --spider http://localhost:8025` |
|
|
16
|
+
| Mailpit | `wget --spider http://localhost:8025` | UI port responds when SMTP is also ready |
|
|
17
17
|
| smtp4dev | `wget --spider http://localhost:80` | UI on internal port 80 |
|
|
18
18
|
| MinIO | `curl -f http://localhost:9000/minio/health/live` | Documented liveness endpoint |
|
|
19
19
|
| Meilisearch | `curl -f http://localhost:7700/health` | Documented |
|
|
@@ -41,11 +41,11 @@ api:
|
|
|
41
41
|
condition: service_healthy # waits for the healthcheck to pass
|
|
42
42
|
redis:
|
|
43
43
|
condition: service_healthy
|
|
44
|
-
|
|
45
|
-
condition:
|
|
44
|
+
mailpit:
|
|
45
|
+
condition: service_healthy
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
`service_healthy` is the strictest gate — no traffic until the healthcheck has passed at least once. Use it for
|
|
48
|
+
`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
49
|
|
|
50
50
|
## Common mistakes
|
|
51
51
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# Mailpit —
|
|
1
|
+
# Mailpit — maintained email capture for local development
|
|
2
2
|
# Env vars: MAILPIT_SMTP_PORT (default 1025), MAILPIT_UI_PORT (default 8025)
|
|
3
|
-
# Application-side SMTP config:
|
|
3
|
+
# Application-side SMTP config: SMTP_HOST=mailpit; SMTP_PORT=1025
|
|
4
4
|
|
|
5
5
|
mailpit:
|
|
6
|
-
image: axllent/mailpit:
|
|
6
|
+
image: axllent/mailpit:v1.30
|
|
7
7
|
restart: unless-stopped
|
|
8
8
|
ports:
|
|
9
9
|
- "${MAILPIT_SMTP_PORT:-1025}:1025"
|
|
@@ -24,4 +24,4 @@ mailpit:
|
|
|
24
24
|
# mailpit_data: {}
|
|
25
25
|
#
|
|
26
26
|
# Prod notes:
|
|
27
|
-
# - DEV ONLY. Do not ship to prod
|
|
27
|
+
# - DEV ONLY. Do not ship to prod; replace it with a real SMTP relay or transactional email API.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# PostgreSQL 18 + pgvector 0.8.2 — relational and vector database
|
|
2
|
+
# Env vars: POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, POSTGRES_PORT (default 5432)
|
|
3
|
+
# Application-side: derive DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
|
|
4
|
+
# The image ships pgvector; create the extension in an application migration with: CREATE EXTENSION IF NOT EXISTS vector;
|
|
5
|
+
|
|
6
|
+
postgres:
|
|
7
|
+
image: pgvector/pgvector:0.8.2-pg18
|
|
8
|
+
restart: unless-stopped
|
|
9
|
+
environment:
|
|
10
|
+
POSTGRES_USER: ${POSTGRES_USER:-app}
|
|
11
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-app}
|
|
12
|
+
POSTGRES_DB: ${POSTGRES_DB:-app}
|
|
13
|
+
ports:
|
|
14
|
+
- "${POSTGRES_PORT:-5432}:5432"
|
|
15
|
+
volumes:
|
|
16
|
+
- postgres_data:/var/lib/postgresql
|
|
17
|
+
healthcheck:
|
|
18
|
+
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-app} -d ${POSTGRES_DB:-app}"]
|
|
19
|
+
interval: 5s
|
|
20
|
+
timeout: 3s
|
|
21
|
+
retries: 10
|
|
22
|
+
start_period: 5s
|
|
23
|
+
|
|
24
|
+
# volumes block to merge:
|
|
25
|
+
# volumes:
|
|
26
|
+
# postgres_data: {}
|
|
27
|
+
#
|
|
28
|
+
# Prod notes:
|
|
29
|
+
# - Use a current patch release derived from PostgreSQL 18 and pgvector 0.8.2 or newer compatible patch.
|
|
30
|
+
# - Move POSTGRES_PASSWORD to a secret and remove the public port mapping.
|
|
31
|
+
# - Keep CREATE EXTENSION and vector indexes in reviewed application migrations.
|