@dewtech/dare-cli 2.16.0 → 3.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/README.md +196 -3
- package/dist/__tests__/confidence.test.d.ts +2 -0
- package/dist/__tests__/confidence.test.d.ts.map +1 -0
- package/dist/__tests__/confidence.test.js +73 -0
- package/dist/__tests__/confidence.test.js.map +1 -0
- package/dist/__tests__/datamodel.test.d.ts +2 -0
- package/dist/__tests__/datamodel.test.d.ts.map +1 -0
- package/dist/__tests__/datamodel.test.js +131 -0
- package/dist/__tests__/datamodel.test.js.map +1 -0
- package/dist/__tests__/dna-detector.test.d.ts +2 -0
- package/dist/__tests__/dna-detector.test.d.ts.map +1 -0
- package/dist/__tests__/dna-detector.test.js +97 -0
- package/dist/__tests__/dna-detector.test.js.map +1 -0
- package/dist/__tests__/dna-facts.test.d.ts +2 -0
- package/dist/__tests__/dna-facts.test.d.ts.map +1 -0
- package/dist/__tests__/dna-facts.test.js +44 -0
- package/dist/__tests__/dna-facts.test.js.map +1 -0
- package/dist/__tests__/graph-renderer.test.d.ts +2 -0
- package/dist/__tests__/graph-renderer.test.d.ts.map +1 -0
- package/dist/__tests__/graph-renderer.test.js +85 -0
- package/dist/__tests__/graph-renderer.test.js.map +1 -0
- package/dist/__tests__/migration.test.d.ts +2 -0
- package/dist/__tests__/migration.test.d.ts.map +1 -0
- package/dist/__tests__/migration.test.js +77 -0
- package/dist/__tests__/migration.test.js.map +1 -0
- package/dist/__tests__/module-detector.test.d.ts +2 -0
- package/dist/__tests__/module-detector.test.d.ts.map +1 -0
- package/dist/__tests__/module-detector.test.js +83 -0
- package/dist/__tests__/module-detector.test.js.map +1 -0
- package/dist/__tests__/refine.test.d.ts +2 -0
- package/dist/__tests__/refine.test.d.ts.map +1 -0
- package/dist/__tests__/refine.test.js +186 -0
- package/dist/__tests__/refine.test.js.map +1 -0
- package/dist/__tests__/reverse-facts.test.d.ts +2 -0
- package/dist/__tests__/reverse-facts.test.d.ts.map +1 -0
- package/dist/__tests__/reverse-facts.test.js +78 -0
- package/dist/__tests__/reverse-facts.test.js.map +1 -0
- package/dist/__tests__/review.test.d.ts +2 -0
- package/dist/__tests__/review.test.d.ts.map +1 -0
- package/dist/__tests__/review.test.js +242 -0
- package/dist/__tests__/review.test.js.map +1 -0
- package/dist/__tests__/update.test.d.ts +2 -0
- package/dist/__tests__/update.test.d.ts.map +1 -0
- package/dist/__tests__/update.test.js +150 -0
- package/dist/__tests__/update.test.js.map +1 -0
- package/dist/__tests__/validate.test.js +65 -65
- package/dist/bin/dare.js +38 -3
- package/dist/bin/dare.js.map +1 -1
- package/dist/commands/blueprint.js +122 -122
- package/dist/commands/dag.d.ts.map +1 -1
- package/dist/commands/dag.js +43 -79
- package/dist/commands/dag.js.map +1 -1
- package/dist/commands/dna.d.ts +3 -0
- package/dist/commands/dna.d.ts.map +1 -0
- package/dist/commands/dna.js +69 -0
- package/dist/commands/dna.js.map +1 -0
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +76 -0
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/migrate.d.ts +3 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +101 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/new.d.ts +16 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +103 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/refine.d.ts +16 -0
- package/dist/commands/refine.d.ts.map +1 -0
- package/dist/commands/refine.js +167 -0
- package/dist/commands/refine.js.map +1 -0
- package/dist/commands/reverse.d.ts +3 -0
- package/dist/commands/reverse.d.ts.map +1 -0
- package/dist/commands/reverse.js +201 -0
- package/dist/commands/reverse.js.map +1 -0
- package/dist/commands/review.d.ts +16 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +106 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/update.d.ts +13 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +149 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/welcome.d.ts +14 -0
- package/dist/commands/welcome.d.ts.map +1 -0
- package/dist/commands/welcome.js +29 -0
- package/dist/commands/welcome.js.map +1 -0
- package/dist/skills/commands/add.d.ts +23 -0
- package/dist/skills/commands/add.d.ts.map +1 -0
- package/dist/skills/commands/add.js +206 -0
- package/dist/skills/commands/add.js.map +1 -0
- package/dist/skills/commands/info.d.ts +14 -0
- package/dist/skills/commands/info.d.ts.map +1 -0
- package/dist/skills/commands/info.js +99 -0
- package/dist/skills/commands/info.js.map +1 -0
- package/dist/skills/commands/list.d.ts +19 -0
- package/dist/skills/commands/list.d.ts.map +1 -0
- package/dist/skills/commands/list.js +163 -0
- package/dist/skills/commands/list.js.map +1 -0
- package/dist/skills/commands/publish.d.ts +56 -0
- package/dist/skills/commands/publish.d.ts.map +1 -0
- package/dist/skills/commands/publish.js +272 -0
- package/dist/skills/commands/publish.js.map +1 -0
- package/dist/skills/commands/remove.d.ts +19 -0
- package/dist/skills/commands/remove.d.ts.map +1 -0
- package/dist/skills/commands/remove.js +96 -0
- package/dist/skills/commands/remove.js.map +1 -0
- package/dist/skills/commands/update.d.ts +31 -0
- package/dist/skills/commands/update.d.ts.map +1 -0
- package/dist/skills/commands/update.js +132 -0
- package/dist/skills/commands/update.js.map +1 -0
- package/dist/skills/index.d.ts +22 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +33 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/manifest.d.ts +54 -0
- package/dist/skills/manifest.d.ts.map +1 -0
- package/dist/skills/manifest.js +162 -0
- package/dist/skills/manifest.js.map +1 -0
- package/dist/skills/registry-local.d.ts +67 -0
- package/dist/skills/registry-local.d.ts.map +1 -0
- package/dist/skills/registry-local.js +130 -0
- package/dist/skills/registry-local.js.map +1 -0
- package/dist/skills/registry-mock.json +109 -0
- package/dist/skills/registry-remote.d.ts +110 -0
- package/dist/skills/registry-remote.d.ts.map +1 -0
- package/dist/skills/registry-remote.js +246 -0
- package/dist/skills/registry-remote.js.map +1 -0
- package/dist/skills/registry.d.ts +49 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +94 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/skills/tests/manifest.spec.d.ts +8 -0
- package/dist/skills/tests/manifest.spec.d.ts.map +1 -0
- package/dist/skills/tests/manifest.spec.js +176 -0
- package/dist/skills/tests/manifest.spec.js.map +1 -0
- package/dist/skills/tests/publish.spec.d.ts +12 -0
- package/dist/skills/tests/publish.spec.d.ts.map +1 -0
- package/dist/skills/tests/publish.spec.js +276 -0
- package/dist/skills/tests/publish.spec.js.map +1 -0
- package/dist/skills/tests/registry-local.spec.d.ts +8 -0
- package/dist/skills/tests/registry-local.spec.d.ts.map +1 -0
- package/dist/skills/tests/registry-local.spec.js +231 -0
- package/dist/skills/tests/registry-local.spec.js.map +1 -0
- package/dist/skills/tests/registry.spec.d.ts +7 -0
- package/dist/skills/tests/registry.spec.d.ts.map +1 -0
- package/dist/skills/tests/registry.spec.js +58 -0
- package/dist/skills/tests/registry.spec.js.map +1 -0
- package/dist/skills/tests/remote-registry.spec.d.ts +9 -0
- package/dist/skills/tests/remote-registry.spec.d.ts.map +1 -0
- package/dist/skills/tests/remote-registry.spec.js +357 -0
- package/dist/skills/tests/remote-registry.spec.js.map +1 -0
- package/dist/skills/tests/update.spec.d.ts +9 -0
- package/dist/skills/tests/update.spec.d.ts.map +1 -0
- package/dist/skills/tests/update.spec.js +166 -0
- package/dist/skills/tests/update.spec.js.map +1 -0
- package/dist/types/Refine.types.d.ts +96 -0
- package/dist/types/Refine.types.d.ts.map +1 -0
- package/dist/types/Refine.types.js +19 -0
- package/dist/types/Refine.types.js.map +1 -0
- package/dist/types/Review.types.d.ts +86 -0
- package/dist/types/Review.types.d.ts.map +1 -0
- package/dist/types/Review.types.js +15 -0
- package/dist/types/Review.types.js.map +1 -0
- package/dist/types/UpdateManifest.types.d.ts +91 -0
- package/dist/types/UpdateManifest.types.d.ts.map +1 -0
- package/dist/types/UpdateManifest.types.js +13 -0
- package/dist/types/UpdateManifest.types.js.map +1 -0
- package/dist/utils/ReviewRunner.d.ts +42 -0
- package/dist/utils/ReviewRunner.d.ts.map +1 -0
- package/dist/utils/ReviewRunner.js +175 -0
- package/dist/utils/ReviewRunner.js.map +1 -0
- package/dist/utils/UpdateApplier.d.ts +42 -0
- package/dist/utils/UpdateApplier.d.ts.map +1 -0
- package/dist/utils/UpdateApplier.js +207 -0
- package/dist/utils/UpdateApplier.js.map +1 -0
- package/dist/utils/UpdateDetector.d.ts +56 -0
- package/dist/utils/UpdateDetector.d.ts.map +1 -0
- package/dist/utils/UpdateDetector.js +164 -0
- package/dist/utils/UpdateDetector.js.map +1 -0
- package/dist/utils/banner.d.ts +28 -0
- package/dist/utils/banner.d.ts.map +1 -0
- package/dist/utils/banner.js +77 -0
- package/dist/utils/banner.js.map +1 -0
- package/dist/utils/banner.spec.d.ts +5 -0
- package/dist/utils/banner.spec.d.ts.map +1 -0
- package/dist/utils/banner.spec.js +253 -0
- package/dist/utils/banner.spec.js.map +1 -0
- package/dist/utils/complexity-analyzer.d.ts +60 -0
- package/dist/utils/complexity-analyzer.d.ts.map +1 -0
- package/dist/utils/complexity-analyzer.js +292 -0
- package/dist/utils/complexity-analyzer.js.map +1 -0
- package/dist/utils/confidence.d.ts +41 -0
- package/dist/utils/confidence.d.ts.map +1 -0
- package/dist/utils/confidence.js +101 -0
- package/dist/utils/confidence.js.map +1 -0
- package/dist/utils/datamodel.d.ts +41 -0
- package/dist/utils/datamodel.d.ts.map +1 -0
- package/dist/utils/datamodel.js +535 -0
- package/dist/utils/datamodel.js.map +1 -0
- package/dist/utils/dna-detector.d.ts +61 -0
- package/dist/utils/dna-detector.d.ts.map +1 -0
- package/dist/utils/dna-detector.js +354 -0
- package/dist/utils/dna-detector.js.map +1 -0
- package/dist/utils/dna-facts.d.ts +13 -0
- package/dist/utils/dna-facts.d.ts.map +1 -0
- package/dist/utils/dna-facts.js +109 -0
- package/dist/utils/dna-facts.js.map +1 -0
- package/dist/utils/excalidraw-renderer.d.ts +11 -71
- package/dist/utils/excalidraw-renderer.d.ts.map +1 -1
- package/dist/utils/excalidraw-renderer.js +29 -162
- package/dist/utils/excalidraw-renderer.js.map +1 -1
- package/dist/utils/graph-renderer.d.ts +115 -0
- package/dist/utils/graph-renderer.d.ts.map +1 -0
- package/dist/utils/graph-renderer.js +216 -0
- package/dist/utils/graph-renderer.js.map +1 -0
- package/dist/utils/migration.d.ts +64 -0
- package/dist/utils/migration.d.ts.map +1 -0
- package/dist/utils/migration.js +183 -0
- package/dist/utils/migration.js.map +1 -0
- package/dist/utils/module-detector.d.ts +46 -0
- package/dist/utils/module-detector.d.ts.map +1 -0
- package/dist/utils/module-detector.js +348 -0
- package/dist/utils/module-detector.js.map +1 -0
- package/dist/utils/project-generator.d.ts.map +1 -1
- package/dist/utils/project-generator.js +273 -254
- package/dist/utils/project-generator.js.map +1 -1
- package/dist/utils/reverse-facts.d.ts +50 -0
- package/dist/utils/reverse-facts.d.ts.map +1 -0
- package/dist/utils/reverse-facts.js +291 -0
- package/dist/utils/reverse-facts.js.map +1 -0
- package/dist/utils/stack-bootstrap.js +371 -371
- package/dist/utils/static-analyzer.d.ts +29 -0
- package/dist/utils/static-analyzer.d.ts.map +1 -0
- package/dist/utils/static-analyzer.js +390 -0
- package/dist/utils/static-analyzer.js.map +1 -0
- package/dist/utils/version-compare.d.ts +27 -0
- package/dist/utils/version-compare.d.ts.map +1 -0
- package/dist/utils/version-compare.js +47 -0
- package/dist/utils/version-compare.js.map +1 -0
- package/package.json +8 -3
- package/templates/DARE-dag-example.yaml +280 -280
- package/templates/UPDATE-MANIFEST.json +48 -0
- package/templates/backend/node-nestjs/.env.example +9 -9
- package/templates/backend/node-nestjs/nest-cli.json +8 -8
- package/templates/backend/node-nestjs/package.json +50 -50
- package/templates/backend/node-nestjs/src/app.controller.ts +12 -12
- package/templates/backend/node-nestjs/src/app.module.ts +15 -15
- package/templates/backend/node-nestjs/src/app.service.ts +8 -8
- package/templates/backend/node-nestjs/src/main.ts +24 -24
- package/templates/backend/node-nestjs/tsconfig.json +21 -21
- package/templates/backend/php-laravel/.env.example +22 -22
- package/templates/backend/php-laravel/app/Http/Controllers/HealthController.php +15 -15
- package/templates/backend/php-laravel/composer.json +40 -40
- package/templates/backend/python-fastapi/.env.example +4 -4
- package/templates/backend/python-fastapi/app/api/router.py +8 -8
- package/templates/backend/python-fastapi/app/core/config.py +20 -20
- package/templates/backend/python-fastapi/main.py +35 -35
- package/templates/backend/python-fastapi/requirements.txt +13 -13
- package/templates/backend/rust-axum/.env.example +3 -3
- package/templates/backend/rust-axum/Cargo.toml +23 -23
- package/templates/backend/rust-axum/src/errors.rs +30 -30
- package/templates/backend/rust-axum/src/main.rs +32 -32
- package/templates/backend/rust-axum/src/routes.rs +6 -6
- package/templates/frontend/leptos-csr/.cargo/config.toml +2 -2
- package/templates/frontend/leptos-csr/Cargo.toml +16 -16
- package/templates/frontend/leptos-csr/Trunk.toml +10 -10
- package/templates/frontend/leptos-csr/index.html +11 -11
- package/templates/frontend/leptos-csr/src/lib.rs +20 -20
- package/templates/frontend/leptos-csr/style/main.scss +19 -19
- package/templates/frontend/leptos-fullstack/.cargo/config.toml +4 -4
- package/templates/frontend/leptos-fullstack/Cargo.toml +56 -56
- package/templates/frontend/leptos-fullstack/src/app.rs +49 -49
- package/templates/frontend/leptos-fullstack/src/lib.rs +9 -9
- package/templates/frontend/leptos-fullstack/src/main.rs +29 -29
- package/templates/frontend/leptos-fullstack/style/main.scss +19 -19
- package/templates/frontend/react/index.html +12 -12
- package/templates/frontend/react/package.json +35 -35
- package/templates/frontend/react/src/App.tsx +25 -25
- package/templates/frontend/react/src/main.tsx +9 -9
- package/templates/frontend/vue/package.json +32 -32
- package/templates/frontend/vue/src/App.vue +7 -7
- package/templates/frontend/vue/src/main.ts +10 -10
- package/templates/frontend/vue/src/router/index.ts +14 -14
- package/templates/frontend/vue/src/views/HomeView.vue +6 -6
- package/templates/hooks/pre-commit-dare-validate +24 -24
- package/templates/ide/antigravity/.agents/skills/dare-ax/SKILL.md +152 -0
- package/templates/ide/antigravity/.agents/skills/dare-blueprint/SKILL.md +180 -36
- package/templates/ide/antigravity/.agents/skills/dare-dag-build/SKILL.md +154 -0
- package/templates/ide/antigravity/.agents/skills/dare-dag-run/SKILL.md +130 -0
- package/templates/ide/antigravity/.agents/skills/dare-dag-runner/SKILL.md +203 -203
- package/templates/ide/antigravity/.agents/skills/dare-dna/SKILL.md +63 -0
- package/templates/ide/antigravity/.agents/skills/dare-docker/SKILL.md +315 -0
- package/templates/ide/antigravity/.agents/skills/dare-frontend-design/SKILL.md +192 -0
- package/templates/ide/antigravity/.agents/skills/dare-laravel-api/SKILL.md +337 -0
- package/templates/ide/antigravity/.agents/skills/dare-layered-design/SKILL.md +166 -0
- package/templates/ide/antigravity/.agents/skills/dare-llm-integration/SKILL.md +217 -0
- package/templates/ide/antigravity/.agents/skills/dare-migrate/SKILL.md +61 -0
- package/templates/ide/antigravity/.agents/skills/dare-quality-telemetry/SKILL.md +187 -0
- package/templates/ide/antigravity/.agents/skills/dare-realtime/SKILL.md +217 -0
- package/templates/ide/antigravity/.agents/skills/dare-refine/SKILL.md +114 -0
- package/templates/ide/antigravity/.agents/skills/dare-reverse/SKILL.md +108 -0
- package/templates/ide/antigravity/.agents/skills/dare-review/SKILL.md +111 -0
- package/templates/ide/antigravity/.agents/skills/dare-rust-leptos/SKILL.md +263 -0
- package/templates/ide/antigravity/.agents/skills/dare-rust-workspace/SKILL.md +275 -275
- package/templates/ide/antigravity/.agents/skills/dare-security/SKILL.md +274 -0
- package/templates/ide/antigravity/.agents/skills/dare-tasks/SKILL.md +265 -224
- package/templates/ide/antigravity/.agents/skills/dare-telemetry/SKILL.md +188 -0
- package/templates/ide/antigravity/.agents/skills/skill-fastapi-api/SKILL.md +343 -0
- package/templates/ide/antigravity/.agents/skills/skill-go-gin-api/SKILL.md +377 -0
- package/templates/ide/antigravity/.agents/skills/skill-mcp-server/SKILL.md +382 -0
- package/templates/ide/antigravity/.agents/skills/skill-nestjs-api/SKILL.md +326 -0
- package/templates/ide/antigravity/.agents/skills/skill-rails-api/SKILL.md +393 -0
- package/templates/ide/antigravity/templates/BLUEPRINT-template.md +193 -193
- package/templates/ide/antigravity/templates/DESIGN-template.md +129 -129
- package/templates/ide/antigravity/templates/TASK-SPEC-template.md +141 -100
- package/templates/ide/claude/.claude/commands/dare-ax.md +131 -0
- package/templates/ide/claude/.claude/commands/dare-blueprint.md +134 -78
- package/templates/ide/claude/.claude/commands/dare-bugfix-design.md +119 -0
- package/templates/ide/claude/.claude/commands/dare-dag-build.md +151 -110
- package/templates/ide/claude/.claude/commands/dare-dag-run.md +109 -109
- package/templates/ide/claude/.claude/commands/dare-dag-runner.md +117 -0
- package/templates/ide/claude/.claude/commands/dare-dag-viz.md +197 -197
- package/templates/ide/claude/.claude/commands/dare-design.md +69 -69
- package/templates/ide/claude/.claude/commands/dare-dna.md +75 -0
- package/templates/ide/claude/.claude/commands/dare-docker.md +207 -0
- package/templates/ide/claude/.claude/commands/dare-execute.md +152 -152
- package/templates/ide/claude/.claude/commands/dare-feature-design.md +147 -0
- package/templates/ide/claude/.claude/commands/dare-frontend-design.md +149 -0
- package/templates/ide/claude/.claude/commands/dare-laravel-api.md +211 -0
- package/templates/ide/claude/.claude/commands/dare-layered-design.md +124 -0
- package/templates/ide/claude/.claude/commands/dare-llm-integration.md +148 -0
- package/templates/ide/claude/.claude/commands/dare-migrate.md +72 -0
- package/templates/ide/claude/.claude/commands/dare-quality-telemetry.md +166 -0
- package/templates/ide/claude/.claude/commands/dare-realtime.md +159 -0
- package/templates/ide/claude/.claude/commands/dare-refine.md +145 -0
- package/templates/ide/claude/.claude/commands/dare-reverse.md +139 -0
- package/templates/ide/claude/.claude/commands/dare-review.md +113 -0
- package/templates/ide/claude/.claude/commands/dare-rust-leptos.md +269 -269
- package/templates/ide/claude/.claude/commands/dare-rust-workspace.md +209 -209
- package/templates/ide/claude/.claude/commands/dare-security.md +232 -232
- package/templates/ide/claude/.claude/commands/dare-tasks.md +70 -70
- package/templates/ide/claude/.claude/commands/dare-telemetry.md +132 -0
- package/templates/ide/claude/.claude/commands/skill-fastapi-api.md +205 -0
- package/templates/ide/claude/.claude/commands/skill-go-gin-api.md +232 -0
- package/templates/ide/claude/.claude/commands/skill-mcp-server.md +228 -0
- package/templates/ide/claude/.claude/commands/skill-nestjs-api.md +210 -0
- package/templates/ide/claude/.claude/commands/skill-rails-api.md +236 -0
- package/templates/ide/claude/.claude/settings.example.json +35 -35
- package/templates/ide/claude/CLAUDE.md +146 -146
- package/templates/ide/claude/templates/BLUEPRINT-template.md +193 -193
- package/templates/ide/claude/templates/DESIGN-template.md +129 -129
- package/templates/ide/claude/templates/TASK-SPEC-template.md +141 -100
- package/templates/ide/cursor/.cursor/commands/dag-viz.md +139 -0
- package/templates/ide/cursor/.cursor/commands/generate-blueprint.md +86 -41
- package/templates/ide/cursor/.cursor/commands/generate-design.md +35 -35
- package/templates/ide/cursor/.cursor/commands/generate-tasks.md +184 -142
- package/templates/ide/cursor/.cursor/commands/refine-task.md +107 -0
- package/templates/ide/cursor/.cursor/commands/review-task.md +91 -0
- package/templates/ide/cursor/.cursor/commands/run-dag.md +110 -110
- package/templates/ide/cursor/.cursor/rules/skill-ax.mdc +263 -0
- package/templates/ide/cursor/.cursor/rules/skill-dag-build.mdc +173 -0
- package/templates/ide/cursor/.cursor/rules/skill-dag-run.mdc +134 -0
- package/templates/ide/cursor/.cursor/rules/skill-dag-runner.mdc +221 -221
- package/templates/ide/cursor/.cursor/rules/skill-dna.mdc +63 -0
- package/templates/ide/cursor/.cursor/rules/skill-fastapi-api.mdc +352 -0
- package/templates/ide/cursor/.cursor/rules/skill-frontend-design.mdc +244 -0
- package/templates/ide/cursor/.cursor/rules/skill-go-gin-api.mdc +371 -0
- package/templates/ide/cursor/.cursor/rules/skill-layered-design.mdc +266 -0
- package/templates/ide/cursor/.cursor/rules/skill-llm-integration.mdc +295 -0
- package/templates/ide/cursor/.cursor/rules/skill-mcp-server.mdc +367 -0
- package/templates/ide/cursor/.cursor/rules/skill-migrate.mdc +58 -0
- package/templates/ide/cursor/.cursor/rules/skill-nestjs-api.mdc +346 -0
- package/templates/ide/cursor/.cursor/rules/skill-quality-telemetry.mdc +248 -0
- package/templates/ide/cursor/.cursor/rules/skill-rails-api.mdc +400 -0
- package/templates/ide/cursor/.cursor/rules/skill-realtime.mdc +262 -0
- package/templates/ide/cursor/.cursor/rules/skill-reverse.mdc +107 -0
- package/templates/ide/cursor/.cursor/rules/skill-rust-leptos.mdc +281 -0
- package/templates/ide/cursor/.cursor/rules/skill-rust-workspace.mdc +312 -312
- package/templates/ide/cursor/.cursor/rules/skill-security.mdc +245 -245
- package/templates/ide/cursor/templates/BLUEPRINT-template.md +193 -193
- package/templates/ide/cursor/templates/DESIGN-template.md +129 -129
- package/templates/ide/cursor/templates/TASK-SPEC-template.md +141 -100
- package/templates/shared/docker-compose.yml +41 -41
- package/dist/__tests__/dag-runner/adapters.test.d.ts +0 -2
- package/dist/__tests__/dag-runner/adapters.test.d.ts.map +0 -1
- package/dist/__tests__/dag-runner/adapters.test.js +0 -134
- package/dist/__tests__/dag-runner/adapters.test.js.map +0 -1
- package/dist/dag-runner/adapters/antigravity.d.ts +0 -6
- package/dist/dag-runner/adapters/antigravity.d.ts.map +0 -1
- package/dist/dag-runner/adapters/antigravity.js +0 -54
- package/dist/dag-runner/adapters/antigravity.js.map +0 -1
- package/dist/dag-runner/adapters/claude.d.ts +0 -6
- package/dist/dag-runner/adapters/claude.d.ts.map +0 -1
- package/dist/dag-runner/adapters/claude.js +0 -48
- package/dist/dag-runner/adapters/claude.js.map +0 -1
- package/dist/dag-runner/adapters/cursor.d.ts +0 -6
- package/dist/dag-runner/adapters/cursor.d.ts.map +0 -1
- package/dist/dag-runner/adapters/cursor.js +0 -58
- package/dist/dag-runner/adapters/cursor.js.map +0 -1
- package/dist/dag-runner/adapters/index.d.ts +0 -46
- package/dist/dag-runner/adapters/index.d.ts.map +0 -1
- package/dist/dag-runner/adapters/index.js +0 -55
- package/dist/dag-runner/adapters/index.js.map +0 -1
- package/dist/dag-runner/utils/timeout.d.ts +0 -27
- package/dist/dag-runner/utils/timeout.d.ts.map +0 -1
- package/dist/dag-runner/utils/timeout.js +0 -55
- package/dist/dag-runner/utils/timeout.js.map +0 -1
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Padrões DARE para APIs REST em Go + Gin (ou stdlib net/http) + sqlc + PostgreSQL. Handlers, services, repositories, middleware, validação via binding tags, JWT, rate limit, swag OpenAPI, testify + httptest.
|
|
3
|
+
globs: **/*.go,go.mod,go.sum,sqlc.yaml,db/queries/*.sql
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: Go/Gin API DARE
|
|
8
|
+
|
|
9
|
+
Você é um desenvolvedor sênior Go especialista em APIs REST. Esta skill garante código **idiomático Go, com erros tipados, contexto sempre propagado, queries seguras via sqlc**, seguindo Layered Design DARE.
|
|
10
|
+
|
|
11
|
+
## Stack canônica
|
|
12
|
+
|
|
13
|
+
- **Go 1.22+** (`slog`, `errors.Is/As`, generics)
|
|
14
|
+
- **Gin** (preferido) ou **stdlib net/http** (Go 1.22+ roteamento OK)
|
|
15
|
+
- **sqlc** para queries seguras (gera código tipado de SQL)
|
|
16
|
+
- **pgx v5** como driver Postgres
|
|
17
|
+
- **go-playground/validator** (via Gin binding tags)
|
|
18
|
+
- **golang-jwt/jwt v5**
|
|
19
|
+
- **swaggo/swag** para OpenAPI
|
|
20
|
+
- **testify** + **httptest**
|
|
21
|
+
- **golangci-lint** + **govulncheck**
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Estrutura
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
.
|
|
29
|
+
├── cmd/server/main.go
|
|
30
|
+
├── internal/
|
|
31
|
+
│ ├── handlers/ ← Handler
|
|
32
|
+
│ ├── services/ ← Service
|
|
33
|
+
│ ├── repositories/ ← Repository
|
|
34
|
+
│ ├── domain/ ← Models + erros sentinela
|
|
35
|
+
│ ├── middleware/ ← auth, logging, recovery
|
|
36
|
+
│ └── config/
|
|
37
|
+
├── db/
|
|
38
|
+
│ ├── migrations/ ← golang-migrate
|
|
39
|
+
│ └── queries/ ← arquivos .sql para sqlc
|
|
40
|
+
├── sqlc.yaml
|
|
41
|
+
└── docs/ ← gerado pelo swag
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Handlers
|
|
47
|
+
|
|
48
|
+
```go
|
|
49
|
+
package handlers
|
|
50
|
+
|
|
51
|
+
import (
|
|
52
|
+
"errors"
|
|
53
|
+
"net/http"
|
|
54
|
+
"github.com/gin-gonic/gin"
|
|
55
|
+
"myapp/internal/domain"
|
|
56
|
+
"myapp/internal/services"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
type UserHandler struct {
|
|
60
|
+
register *services.RegisterUser
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func NewUserHandler(r *services.RegisterUser) *UserHandler {
|
|
64
|
+
return &UserHandler{register: r}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// @Summary Create user
|
|
68
|
+
// @Tags users
|
|
69
|
+
// @Accept json
|
|
70
|
+
// @Produce json
|
|
71
|
+
// @Param user body CreateUserDTO true "user payload"
|
|
72
|
+
// @Success 201 {object} UserResponse
|
|
73
|
+
// @Failure 409
|
|
74
|
+
// @Router /users [post]
|
|
75
|
+
func (h *UserHandler) Create(c *gin.Context) {
|
|
76
|
+
var dto CreateUserDTO
|
|
77
|
+
if err := c.ShouldBindJSON(&dto); err != nil {
|
|
78
|
+
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
user, err := h.register.Execute(c.Request.Context(), dto.ToService())
|
|
82
|
+
if err != nil {
|
|
83
|
+
if errors.Is(err, domain.ErrUserAlreadyExists) {
|
|
84
|
+
c.JSON(http.StatusConflict, gin.H{"error": "USER_EXISTS"})
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
c.JSON(http.StatusInternalServerError, gin.H{"error": "INTERNAL"})
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
c.JSON(http.StatusCreated, ToUserResponse(user))
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## DTOs (binding tags)
|
|
97
|
+
|
|
98
|
+
```go
|
|
99
|
+
type CreateUserDTO struct {
|
|
100
|
+
Email string `json:"email" binding:"required,email"`
|
|
101
|
+
Name string `json:"name" binding:"required,min=1,max=255"`
|
|
102
|
+
Password string `json:"password" binding:"required,min=12"`
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
func (d CreateUserDTO) ToService() services.RegisterUserInput {
|
|
106
|
+
return services.RegisterUserInput{Email: d.Email, Name: d.Name, Password: d.Password}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
type UserResponse struct {
|
|
110
|
+
ID int64 `json:"id"`
|
|
111
|
+
Email string `json:"email"`
|
|
112
|
+
Name string `json:"name"`
|
|
113
|
+
CreatedAt time.Time `json:"createdAt"`
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Services
|
|
120
|
+
|
|
121
|
+
```go
|
|
122
|
+
type RegisterUser struct {
|
|
123
|
+
repo *repositories.UserRepository
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
type RegisterUserInput struct {
|
|
127
|
+
Email, Name, Password string
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
func (s *RegisterUser) Execute(ctx context.Context, in RegisterUserInput) (*domain.User, error) {
|
|
131
|
+
exists, err := s.repo.ExistsByEmail(ctx, in.Email)
|
|
132
|
+
if err != nil { return nil, err }
|
|
133
|
+
if exists { return nil, domain.ErrUserAlreadyExists }
|
|
134
|
+
return s.repo.Create(ctx, repositories.CreateUserParams{
|
|
135
|
+
Email: in.Email,
|
|
136
|
+
Name: in.Name,
|
|
137
|
+
PasswordHash: hashPassword(in.Password),
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Repositories (sqlc)
|
|
145
|
+
|
|
146
|
+
```sql
|
|
147
|
+
-- db/queries/users.sql
|
|
148
|
+
-- name: ExistsUserByEmail :one
|
|
149
|
+
SELECT EXISTS(SELECT 1 FROM users WHERE email = $1);
|
|
150
|
+
|
|
151
|
+
-- name: CreateUser :one
|
|
152
|
+
INSERT INTO users (email, name, password_hash)
|
|
153
|
+
VALUES ($1, $2, $3)
|
|
154
|
+
RETURNING id, email, name, created_at;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
```go
|
|
158
|
+
type UserRepository struct {
|
|
159
|
+
q *sqlc.Queries
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
func (r *UserRepository) ExistsByEmail(ctx context.Context, email string) (bool, error) {
|
|
163
|
+
return r.q.ExistsUserByEmail(ctx, email)
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Domain
|
|
170
|
+
|
|
171
|
+
```go
|
|
172
|
+
package domain
|
|
173
|
+
|
|
174
|
+
import (
|
|
175
|
+
"errors"
|
|
176
|
+
"time"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
var (
|
|
180
|
+
ErrUserAlreadyExists = errors.New("user already exists")
|
|
181
|
+
ErrUserNotFound = errors.New("user not found")
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
type User struct {
|
|
185
|
+
ID int64
|
|
186
|
+
Email string
|
|
187
|
+
Name string
|
|
188
|
+
CreatedAt time.Time
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Middleware (JWT)
|
|
195
|
+
|
|
196
|
+
```go
|
|
197
|
+
func AuthRequired(secret []byte) gin.HandlerFunc {
|
|
198
|
+
return func(c *gin.Context) {
|
|
199
|
+
tokenStr := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
|
|
200
|
+
token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (any, error) { return secret, nil })
|
|
201
|
+
if err != nil || !token.Valid {
|
|
202
|
+
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
c.Set("user_id", token.Claims.(jwt.MapClaims)["sub"])
|
|
206
|
+
c.Next()
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Rate limiting
|
|
214
|
+
|
|
215
|
+
```go
|
|
216
|
+
import "github.com/gin-contrib/limit"
|
|
217
|
+
|
|
218
|
+
router.Use(limit.MaxAllowed(20)) // global
|
|
219
|
+
login := router.Group("/auth").Use(myRateLimiter("5/15m"))
|
|
220
|
+
login.POST("/login", authHandler.Login)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## OpenAPI (swag)
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
swag init -g cmd/server/main.go -o docs
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```go
|
|
232
|
+
// cmd/server/main.go
|
|
233
|
+
// @title Projeto API
|
|
234
|
+
// @version 1.0
|
|
235
|
+
import _ "myapp/docs"
|
|
236
|
+
import (
|
|
237
|
+
ginSwagger "github.com/swaggo/gin-swagger"
|
|
238
|
+
swaggerFiles "github.com/swaggo/files"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
|
242
|
+
router.GET("/openapi.json", func(c *gin.Context) {
|
|
243
|
+
c.File("docs/swagger.json")
|
|
244
|
+
})
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Config (env)
|
|
250
|
+
|
|
251
|
+
```go
|
|
252
|
+
type Config struct {
|
|
253
|
+
DatabaseURL string
|
|
254
|
+
JWTSecret []byte
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
func Load() (*Config, error) {
|
|
258
|
+
return &Config{
|
|
259
|
+
DatabaseURL: os.Getenv("DATABASE_URL"),
|
|
260
|
+
JWTSecret: []byte(os.Getenv("JWT_SECRET")),
|
|
261
|
+
}, nil
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Testes
|
|
268
|
+
|
|
269
|
+
```go
|
|
270
|
+
// Service unit
|
|
271
|
+
func TestRegisterUser_DuplicateEmail(t *testing.T) {
|
|
272
|
+
repo := &mocks.UserRepository{}
|
|
273
|
+
repo.On("ExistsByEmail", mock.Anything, "jane@example.com").Return(true, nil)
|
|
274
|
+
svc := services.NewRegisterUser(repo)
|
|
275
|
+
_, err := svc.Execute(ctx, services.RegisterUserInput{Email: "jane@example.com"})
|
|
276
|
+
assert.ErrorIs(t, err, domain.ErrUserAlreadyExists)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Handler via httptest
|
|
280
|
+
func TestUserHandler_Create(t *testing.T) {
|
|
281
|
+
r := gin.New()
|
|
282
|
+
r.POST("/users", h.Create)
|
|
283
|
+
body := `{"email":"jane@example.com","name":"Jane","password":"longsecret123"}`
|
|
284
|
+
req := httptest.NewRequest("POST", "/users", strings.NewReader(body))
|
|
285
|
+
req.Header.Set("Content-Type", "application/json")
|
|
286
|
+
w := httptest.NewRecorder()
|
|
287
|
+
r.ServeHTTP(w, req)
|
|
288
|
+
assert.Equal(t, http.StatusCreated, w.Code)
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Antipatterns
|
|
295
|
+
|
|
296
|
+
| AP | Antipattern | Correção |
|
|
297
|
+
|---|---|---|
|
|
298
|
+
| AP-01 | `database/sql` no handler | Repository + sqlc |
|
|
299
|
+
| AP-02 | Validação manual | `binding:` tags + validator |
|
|
300
|
+
| AP-03 | Lógica no handler | Service |
|
|
301
|
+
| AP-04 | Retornar `db.User` direto | `UserResponse` DTO |
|
|
302
|
+
| AP-05 | Secret hardcoded | `os.Getenv` ou viper |
|
|
303
|
+
| AP-06 | Sem rate limit em login | middleware |
|
|
304
|
+
| AP-07 | `panic` em handler | recovery middleware |
|
|
305
|
+
| AP-08 | Context não propagado | sempre `ctx context.Context` |
|
|
306
|
+
| AP-09 | SQL com `fmt.Sprintf` | sqlc / parametrizado |
|
|
307
|
+
| AP-10 | `errors.New` espalhado | sentinela em `domain/errors.go` |
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Segurança
|
|
312
|
+
|
|
313
|
+
- Senhas: `argon2.IDKey` (`golang.org/x/crypto/argon2`)
|
|
314
|
+
- JWT: HS256 secret ≥ 32 bytes, ou RS256 par de chaves
|
|
315
|
+
- Headers: `secure` middleware
|
|
316
|
+
- CORS: `github.com/gin-contrib/cors` com origens específicas
|
|
317
|
+
- Rate limit em login (5/15min)
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## CI
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
go vet ./...
|
|
325
|
+
golangci-lint run
|
|
326
|
+
go test ./... -race -cover
|
|
327
|
+
govulncheck ./...
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Aplicação por fase DARE
|
|
333
|
+
|
|
334
|
+
### Design
|
|
335
|
+
- Endpoints REST com método/path/auth
|
|
336
|
+
- Schemas de input/output
|
|
337
|
+
- Erros sentinela esperados
|
|
338
|
+
|
|
339
|
+
### Blueprint
|
|
340
|
+
- Estrutura `internal/{handlers,services,repositories,domain}`
|
|
341
|
+
- `sqlc.yaml` configurado
|
|
342
|
+
- Migrations `golang-migrate`
|
|
343
|
+
|
|
344
|
+
### Tasks
|
|
345
|
+
- Por feature: 5 tasks (Migration, sqlc query, Repository, Service, Handler+DTO)
|
|
346
|
+
- Task de configuração middleware + swag + golangci-lint
|
|
347
|
+
|
|
348
|
+
### Execute
|
|
349
|
+
- Ralph Loop:
|
|
350
|
+
```bash
|
|
351
|
+
go vet ./... && golangci-lint run && go test ./... -race && govulncheck ./...
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Checklist final
|
|
357
|
+
|
|
358
|
+
- [ ] Go 1.22+, golangci-lint configurado
|
|
359
|
+
- [ ] sqlc gerando queries a partir de SQL
|
|
360
|
+
- [ ] Handlers magros (apenas bind + chamada Service)
|
|
361
|
+
- [ ] Services com `ctx context.Context` como 1º param
|
|
362
|
+
- [ ] Erros sentinela em `domain/errors.go`
|
|
363
|
+
- [ ] DTOs com `binding:` tags
|
|
364
|
+
- [ ] JWT secret via env
|
|
365
|
+
- [ ] Rate limit em login
|
|
366
|
+
- [ ] OpenAPI gerado em `docs/swagger.json`
|
|
367
|
+
- [ ] Cobertura ≥ 70%
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
Skill licenciada MIT — parte do DARE Method v3.
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Layered Design — enforce arquitetura estrita Handler→Service→Repository→Model em todos os projetos DARE, independente de linguagem. Inspirado em "Layered Design for Ruby on Rails Applications" de Vladimir Dementyev (Evil Martians).
|
|
3
|
+
globs: **/*.rb,**/*.php,**/*.py,**/*.ts,**/*.tsx,**/*.js,**/*.rs,**/*.go,DARE/BLUEPRINT.md,DARE/DESIGN.md
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: Layered Design DARE
|
|
8
|
+
|
|
9
|
+
Você é um arquiteto de software especialista em **Layered Design**. Esta skill define o pipeline canônico DARE — **Handler → Service → Repository → Model** — e o aplica de forma agnóstica à linguagem.
|
|
10
|
+
|
|
11
|
+
## Por que Layered Design
|
|
12
|
+
|
|
13
|
+
Em projetos legados, o problema **#1** não é falta de testes — é mistura de camadas. Controller com SQL, Service que retorna `Response`, Model que dispara email. Resultado: nada é testável sem subir o framework inteiro.
|
|
14
|
+
|
|
15
|
+
A solução é tornar **cada camada uma fronteira intransponível**, com responsabilidades claras e lint que falha o CI se alguém pular um nível.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## As 4 camadas
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
┌────────────────────────────────────────────┐
|
|
23
|
+
│ Handler (HTTP, gRPC, CLI, queue worker) │ ← entrada
|
|
24
|
+
└────────────────────────────────────────────┘
|
|
25
|
+
↓ chama
|
|
26
|
+
┌────────────────────────────────────────────┐
|
|
27
|
+
│ Service (1 operação de negócio) │ ← coração
|
|
28
|
+
└────────────────────────────────────────────┘
|
|
29
|
+
↓ usa
|
|
30
|
+
┌────────────────────────────────────────────┐
|
|
31
|
+
│ Repository (acesso a dados) │ ← I/O
|
|
32
|
+
└────────────────────────────────────────────┘
|
|
33
|
+
↓ retorna
|
|
34
|
+
┌────────────────────────────────────────────┐
|
|
35
|
+
│ Model (entidade do domínio) │ ← núcleo
|
|
36
|
+
└────────────────────────────────────────────┘
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Handler — responsabilidades
|
|
40
|
+
|
|
41
|
+
| Faz | Não faz |
|
|
42
|
+
|---|---|
|
|
43
|
+
| Recebe request (HTTP/gRPC/CLI/queue) | Acessa Repository direto |
|
|
44
|
+
| Valida input (FormRequest/Pydantic/Zod/serde) | Contém lógica de negócio |
|
|
45
|
+
| Chama **um** Service | Faz SQL ou query inline |
|
|
46
|
+
| Formata e retorna response | Instancia Service com `new` (use injeção) |
|
|
47
|
+
|
|
48
|
+
### Service — responsabilidades
|
|
49
|
+
|
|
50
|
+
| Faz | Não faz |
|
|
51
|
+
|---|---|
|
|
52
|
+
| Implementa **uma** operação (`RegisterUser`) | Conhece HTTP (status, headers) |
|
|
53
|
+
| Orquestra Repositories | Conhece framework web |
|
|
54
|
+
| Valida regras de negócio | Faz SQL inline |
|
|
55
|
+
| Lança exceções de domínio (`UserAlreadyExists`) | É uma God Class com 30 métodos |
|
|
56
|
+
|
|
57
|
+
### Repository — responsabilidades
|
|
58
|
+
|
|
59
|
+
| Faz | Não faz |
|
|
60
|
+
|---|---|
|
|
61
|
+
| Abstrai persistência (DB, cache, API externa) | Retorna HTTP status code |
|
|
62
|
+
| Retorna Model ou primitivo | Lança exceções de domínio (retorna `Option`/`null`) |
|
|
63
|
+
| Esconde SQL/HTTP externo | Contém regra de negócio |
|
|
64
|
+
|
|
65
|
+
### Model — responsabilidades
|
|
66
|
+
|
|
67
|
+
| Faz | Não faz |
|
|
68
|
+
|---|---|
|
|
69
|
+
| Representa entidade do domínio | Conhece HTTP/DB/framework |
|
|
70
|
+
| Carrega invariantes (`Email` válido, `Money` ≥ 0) | Importa de Service/Repository/Handler |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Métricas (todas verificáveis em CI)
|
|
75
|
+
|
|
76
|
+
| ID | Métrica | Como medir |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| M-01 | 100% dos Services têm teste unitário (sem DB/HTTP real) | linter checa diretório `tests/services/` |
|
|
79
|
+
| M-02 | 0% de chamadas Handler→Repository diretas | grep AST nos controllers |
|
|
80
|
+
| M-03 | 100% dos Handlers usam injeção (sem `new Service()` inline) | grep nos controllers |
|
|
81
|
+
| M-04 | 100% dos Repositories são agnósticos (não retornam HTTP status) | grep nos repositories |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Antipatterns (CI falha se aparecer)
|
|
86
|
+
|
|
87
|
+
| AP | Antipattern | Sinal | Correção |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| AP-01 | Handler→Repository direto | `controller.repo.find()` | Criar Service entre eles |
|
|
90
|
+
| AP-02 | Service com SQL inline | `db.query("SELECT…")` em Service | Mover para Repository |
|
|
91
|
+
| AP-03 | Repository lança exceção de domínio | `throw UserNotFound` em Repo | Retornar `null`/`Option`/`Maybe` |
|
|
92
|
+
| AP-04 | Model importa Service | `Model.payment_service` | Refatorar — Service usa Model, não o inverso |
|
|
93
|
+
| AP-05 | God Service (>20 métodos) | `UserService` com tudo | Quebrar em `RegisterUser`, `ResetPassword`, … |
|
|
94
|
+
| AP-06 | Fat Controller (>100 linhas) | controller monstro | Mover lógica para Service |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Tradução por linguagem/framework
|
|
99
|
+
|
|
100
|
+
| Camada DARE | Laravel | NestJS | FastAPI | Rails | Rust/Axum | Go/Gin |
|
|
101
|
+
|---|---|---|---|---|---|---|
|
|
102
|
+
| Handler | `Http/Controllers/` | `*.controller.ts` | `routers/*.py` | `app/controllers/` | `handlers/*.rs` | `handlers/*.go` |
|
|
103
|
+
| Service | `Services/` | `*.service.ts` | `services/*.py` | `app/services/` | `services/*.rs` | `services/*.go` |
|
|
104
|
+
| Repository | `Repositories/` | `*.repository.ts` | `repositories/*.py` | `app/repositories/` | `repositories/*.rs` | `repositories/*.go` |
|
|
105
|
+
| Model | `Models/` | `entities/*.ts` | `models/*.py` | `app/models/` | `domain/*.rs` | `models/*.go` |
|
|
106
|
+
| Presenter (opcional) | `Resources/` | `dto/` | `schemas/` | `app/serializers/` | `presenters/*.rs` | `dto/*.go` |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Exemplos por stack
|
|
111
|
+
|
|
112
|
+
### Laravel
|
|
113
|
+
|
|
114
|
+
```php
|
|
115
|
+
// Handler
|
|
116
|
+
class UserController {
|
|
117
|
+
public function __construct(private RegisterUser $service) {}
|
|
118
|
+
|
|
119
|
+
public function store(StoreUserRequest $req) {
|
|
120
|
+
$user = $this->service->execute($req->validated());
|
|
121
|
+
return new UserResource($user);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Service
|
|
126
|
+
class RegisterUser {
|
|
127
|
+
public function __construct(private UserRepository $repo) {}
|
|
128
|
+
public function execute(array $data): User {
|
|
129
|
+
if ($this->repo->existsByEmail($data['email'])) {
|
|
130
|
+
throw new UserAlreadyExistsException();
|
|
131
|
+
}
|
|
132
|
+
return $this->repo->create($data);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Repository
|
|
137
|
+
class UserRepository {
|
|
138
|
+
public function existsByEmail(string $email): bool { ... }
|
|
139
|
+
public function create(array $data): User { ... }
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### NestJS
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
@Controller('users')
|
|
147
|
+
export class UsersController {
|
|
148
|
+
constructor(private register: RegisterUser) {}
|
|
149
|
+
|
|
150
|
+
@Post()
|
|
151
|
+
async store(@Body() dto: CreateUserDto) {
|
|
152
|
+
return this.register.execute(dto);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
@Injectable()
|
|
157
|
+
export class RegisterUser {
|
|
158
|
+
constructor(private repo: UserRepository) {}
|
|
159
|
+
|
|
160
|
+
async execute(dto: CreateUserDto): Promise<User> {
|
|
161
|
+
if (await this.repo.existsByEmail(dto.email)) {
|
|
162
|
+
throw new UserAlreadyExistsError();
|
|
163
|
+
}
|
|
164
|
+
return this.repo.create(dto);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### FastAPI
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
# Handler
|
|
173
|
+
@router.post("/users")
|
|
174
|
+
async def store(payload: UserIn, service: RegisterUser = Depends()):
|
|
175
|
+
return await service.execute(payload)
|
|
176
|
+
|
|
177
|
+
# Service
|
|
178
|
+
class RegisterUser:
|
|
179
|
+
def __init__(self, repo: UserRepository = Depends()):
|
|
180
|
+
self.repo = repo
|
|
181
|
+
async def execute(self, payload: UserIn) -> User:
|
|
182
|
+
if await self.repo.exists_by_email(payload.email):
|
|
183
|
+
raise UserAlreadyExistsError()
|
|
184
|
+
return await self.repo.create(payload)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Rust/Axum
|
|
188
|
+
|
|
189
|
+
```rust
|
|
190
|
+
// Handler
|
|
191
|
+
async fn create_user(
|
|
192
|
+
State(svc): State<Arc<RegisterUser>>,
|
|
193
|
+
Json(input): Json<CreateUser>,
|
|
194
|
+
) -> Result<Json<User>, AppError> {
|
|
195
|
+
let user = svc.execute(input).await?;
|
|
196
|
+
Ok(Json(user))
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Service
|
|
200
|
+
pub struct RegisterUser {
|
|
201
|
+
repo: Arc<dyn UserRepository>,
|
|
202
|
+
}
|
|
203
|
+
impl RegisterUser {
|
|
204
|
+
pub async fn execute(&self, input: CreateUser) -> Result<User, DomainError> {
|
|
205
|
+
if self.repo.exists_by_email(&input.email).await? {
|
|
206
|
+
return Err(DomainError::UserAlreadyExists);
|
|
207
|
+
}
|
|
208
|
+
self.repo.create(input).await
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Cobertura de testes
|
|
216
|
+
|
|
217
|
+
**Service = teste unitário rápido (mock do Repository):**
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
describe('RegisterUser', () => {
|
|
221
|
+
it('falha se email já existe', async () => {
|
|
222
|
+
const repo = { existsByEmail: jest.fn().mockResolvedValue(true) };
|
|
223
|
+
const sut = new RegisterUser(repo as any);
|
|
224
|
+
await expect(sut.execute({email: 'x@y.com'})).rejects.toThrow();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Repository = teste de integração (subir Postgres real ou usar testcontainers).**
|
|
230
|
+
|
|
231
|
+
**Handler = teste E2E HTTP (`supertest`, `httpx`, `reqwest`).**
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Aplicação por fase DARE
|
|
236
|
+
|
|
237
|
+
### Design
|
|
238
|
+
|
|
239
|
+
DESIGN.md deve listar bounded contexts → cada um vira pasta de Services.
|
|
240
|
+
|
|
241
|
+
### Blueprint
|
|
242
|
+
|
|
243
|
+
BLUEPRINT.md deve ter diagrama das camadas com setas explícitas (Handler→Service→Repository→Model).
|
|
244
|
+
|
|
245
|
+
### Tasks
|
|
246
|
+
|
|
247
|
+
Cada feature gera 4 tasks mínimas: criar Model, criar Repository, criar Service (com teste unitário), criar Handler.
|
|
248
|
+
|
|
249
|
+
### Execute
|
|
250
|
+
|
|
251
|
+
Ralph Loop falha se grep detectar AP-01 a AP-06.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Checklist final
|
|
256
|
+
|
|
257
|
+
- [ ] Pastas mapeadas para as 4 camadas
|
|
258
|
+
- [ ] Lint AP-01 a AP-06 no CI
|
|
259
|
+
- [ ] Services 100% testados unitariamente (sem DB)
|
|
260
|
+
- [ ] Repositories testados via integração (testcontainers)
|
|
261
|
+
- [ ] Handlers magros (< 50 linhas)
|
|
262
|
+
- [ ] Models sem dependência de framework
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
Skill licenciada MIT — parte do DARE Method v3.
|