@dewtech/dare-cli 2.17.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 +98 -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.js +49 -49
- 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.js +38 -38
- package/dist/__tests__/validate.test.js +65 -65
- package/dist/bin/dare.js +32 -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/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/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/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/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/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.js +252 -252
- 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/package.json +8 -3
- package/templates/DARE-dag-example.yaml +280 -280
- package/templates/UPDATE-MANIFEST.json +48 -48
- 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-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 -114
- package/templates/ide/antigravity/.agents/skills/dare-reverse/SKILL.md +108 -0
- package/templates/ide/antigravity/.agents/skills/dare-review/SKILL.md +111 -111
- 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 -265
- 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 -141
- package/templates/ide/claude/.claude/commands/dare-ax.md +131 -0
- package/templates/ide/claude/.claude/commands/dare-blueprint.md +134 -134
- package/templates/ide/claude/.claude/commands/dare-bugfix-design.md +119 -0
- package/templates/ide/claude/.claude/commands/dare-dag-build.md +151 -151
- 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 -145
- package/templates/ide/claude/.claude/commands/dare-reverse.md +139 -0
- package/templates/ide/claude/.claude/commands/dare-review.md +113 -113
- 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 -141
- package/templates/ide/cursor/.cursor/commands/dag-viz.md +139 -0
- package/templates/ide/cursor/.cursor/commands/generate-blueprint.md +86 -86
- package/templates/ide/cursor/.cursor/commands/generate-design.md +35 -35
- package/templates/ide/cursor/.cursor/commands/generate-tasks.md +184 -184
- package/templates/ide/cursor/.cursor/commands/refine-task.md +107 -107
- package/templates/ide/cursor/.cursor/commands/review-task.md +91 -91
- 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 -141
- 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,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dare-telemetry
|
|
3
|
+
description: Rastreamento de tokens e modelos de IA consumidos em cada etapa do Método DARE. Gera DARE/TELEMETRY.md com modelo usado, tokens estimados, tempo e tentativas (Ralph Loop) por comando — para auditoria, monitoramento de uso e otimização de custos.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DARE Telemetry Skill
|
|
7
|
+
|
|
8
|
+
Você é um especialista em observabilidade e monitoramento de uso de IA. Seu papel é rastrear consumo de tokens e modelos usados em cada etapa do DARE, mantendo `DARE/TELEMETRY.md` atualizado.
|
|
9
|
+
|
|
10
|
+
> **Diferença com `dare-quality-telemetry`:**
|
|
11
|
+
> - `dare-telemetry` (esta) — rastreia **uso de IA** (modelos, tokens, tempo) por comando DARE
|
|
12
|
+
> - `dare-quality-telemetry` — agrega **métricas de qualidade** das skills (M-01 a M-04)
|
|
13
|
+
|
|
14
|
+
## Quando usar
|
|
15
|
+
|
|
16
|
+
- Ao final de cada comando DARE executado
|
|
17
|
+
- Para gerar relatório periódico de uso de IA
|
|
18
|
+
- Para auditoria de compliance (qual IA foi usada, onde)
|
|
19
|
+
- Para otimização de custos (qual etapa consome mais)
|
|
20
|
+
|
|
21
|
+
## Modelos rastreáveis
|
|
22
|
+
|
|
23
|
+
Independente do IDE/agente:
|
|
24
|
+
|
|
25
|
+
| Modelo | Provider | Características | Melhor para |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Claude Opus 4.7 | Anthropic | Análise profunda, refactor longo | Design, blueprint, security review |
|
|
28
|
+
| Claude Sonnet 4.5 | Anthropic | Equilíbrio velocidade/qualidade | Execução de tasks |
|
|
29
|
+
| GPT-4 Turbo | OpenAI | Versátil | Tarefas gerais |
|
|
30
|
+
| Gemini 2.0 Flash | Google | Ultra rápido | Tasks simples, processamento em batch |
|
|
31
|
+
| Modelos locais (Ollama) | Self-hosted | Privacidade total | Dados sensíveis |
|
|
32
|
+
|
|
33
|
+
## Estrutura `DARE/TELEMETRY.md`
|
|
34
|
+
|
|
35
|
+
```markdown
|
|
36
|
+
# Telemetria do Projeto: [Nome]
|
|
37
|
+
|
|
38
|
+
## Resumo Executivo
|
|
39
|
+
- **Projeto:** [Nome]
|
|
40
|
+
- **Data de início:** [ISO 8601]
|
|
41
|
+
- **Tokens totais processados:** [Número]
|
|
42
|
+
- **Modelos utilizados:** [Lista]
|
|
43
|
+
- **Tempo total de execução:** [Tempo]
|
|
44
|
+
- **Custo estimado:** $[X]
|
|
45
|
+
|
|
46
|
+
## Detalhamento por Etapa
|
|
47
|
+
|
|
48
|
+
### 1. Design (`/dare-design`)
|
|
49
|
+
- **Data/Hora:** [Timestamp]
|
|
50
|
+
- **Modelo:** Claude Opus 4.7
|
|
51
|
+
- **Tokens estimados (in/out):** 7,390 / 1,250
|
|
52
|
+
- **Tempo de execução:** 45 segundos
|
|
53
|
+
- **Comando:** `/dare-design "Criar API de autenticação"`
|
|
54
|
+
- **Resultado:** DESIGN.md gerado, 12 RFs, 8 RNFs, 5 RS
|
|
55
|
+
- **Observações:** [Ajustes manuais necessários, etc.]
|
|
56
|
+
|
|
57
|
+
### 2. Blueprint (`/dare-blueprint`)
|
|
58
|
+
- **Data/Hora:** [Timestamp]
|
|
59
|
+
- **Modelo:** Claude Opus 4.7
|
|
60
|
+
- **Tokens estimados (in/out):** 21,373 / 4,800
|
|
61
|
+
- **Tempo:** 2 min
|
|
62
|
+
- **Arquivo processado:** DARE/DESIGN.md
|
|
63
|
+
- **Resultado:** BLUEPRINT.md com 8 fases, 25 tabelas, 4 diagramas Mermaid
|
|
64
|
+
|
|
65
|
+
### 3. Tasks (`/dare-tasks`)
|
|
66
|
+
- **Tokens estimados:** 33,912 / 8,200
|
|
67
|
+
- **Tempo:** 3 min 20 seg
|
|
68
|
+
- **Arquivo processado:** DARE/BLUEPRINT.md
|
|
69
|
+
- **Tasks geradas:** 12
|
|
70
|
+
|
|
71
|
+
### 4. Execute Tasks (`/dare-execute`)
|
|
72
|
+
|
|
73
|
+
- **task-001 — Migration de Users**
|
|
74
|
+
- Modelo: Claude Sonnet 4.5
|
|
75
|
+
- Tokens: 7,801 / 2,500
|
|
76
|
+
- Tempo: 1 min 30 seg
|
|
77
|
+
- Tentativas (Ralph Loop): 1
|
|
78
|
+
- Status: ✓ Sucesso
|
|
79
|
+
|
|
80
|
+
- **task-002 — AuthController**
|
|
81
|
+
- Modelo: Claude Sonnet 4.5
|
|
82
|
+
- Tokens: 11,357 / 3,200
|
|
83
|
+
- Tempo: 2 min
|
|
84
|
+
- Tentativas: 2 (1 falha por typo)
|
|
85
|
+
- Status: ✓ Sucesso
|
|
86
|
+
|
|
87
|
+
## Análise
|
|
88
|
+
|
|
89
|
+
| Etapa | Tokens in/out | % do total | Tempo |
|
|
90
|
+
|---|---|---|---|
|
|
91
|
+
| Design | 7,390 / 1,250 | 5% | 45 seg |
|
|
92
|
+
| Blueprint | 21,373 / 4,800 | 15% | 2 min |
|
|
93
|
+
| Tasks | 33,912 / 8,200 | 24% | 3 min 20 seg |
|
|
94
|
+
| Execute (12 tasks) | 85,234 / 24,000 | 56% | 25 min |
|
|
95
|
+
| **TOTAL** | **147,909 / 38,250** | **100%** | **~31 min** |
|
|
96
|
+
|
|
97
|
+
## Modelos utilizados
|
|
98
|
+
|
|
99
|
+
- Claude Opus 4.7: 62,675 tokens (42%) — design + blueprint + tasks
|
|
100
|
+
- Claude Sonnet 4.5: 85,234 tokens (58%) — execução de tasks
|
|
101
|
+
|
|
102
|
+
## Custo estimado
|
|
103
|
+
|
|
104
|
+
| Modelo | Tokens in | Tokens out | $/M in | $/M out | Total |
|
|
105
|
+
|---|---|---|---|---|---|
|
|
106
|
+
| Opus 4.7 | 62,675 | 14,250 | $15 | $75 | $2.01 |
|
|
107
|
+
| Sonnet 4.5 | 85,234 | 24,000 | $3 | $15 | $0.62 |
|
|
108
|
+
| **Total** | | | | | **$2.63** |
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Como aplicar
|
|
112
|
+
|
|
113
|
+
### Passo 1: Após `/dare-design`
|
|
114
|
+
|
|
115
|
+
Adicione entrada na seção Design com:
|
|
116
|
+
- Timestamp
|
|
117
|
+
- Modelo do agente (perguntar ao usuário se não souber automaticamente)
|
|
118
|
+
- Tokens estimados (in/out) — pegar do output do modelo se disponível
|
|
119
|
+
- Tempo de execução
|
|
120
|
+
- Comando executado
|
|
121
|
+
- Observações qualitativas
|
|
122
|
+
|
|
123
|
+
### Passo 2: Após `/dare-blueprint`
|
|
124
|
+
|
|
125
|
+
Idem. Adicione tabelas e diagramas gerados como resultado.
|
|
126
|
+
|
|
127
|
+
### Passo 3: Após `/dare-tasks`
|
|
128
|
+
|
|
129
|
+
Inclua número de tasks geradas, complexidade média.
|
|
130
|
+
|
|
131
|
+
### Passo 4: Após cada `/dare-execute`
|
|
132
|
+
|
|
133
|
+
Para cada task:
|
|
134
|
+
- Modelo usado
|
|
135
|
+
- Tokens
|
|
136
|
+
- Tempo
|
|
137
|
+
- **Tentativas no Ralph Loop** (importante — se >2, task precisa refino)
|
|
138
|
+
- Status (Sucesso/Falha)
|
|
139
|
+
|
|
140
|
+
### Passo 5: Recompilar análise + custos
|
|
141
|
+
|
|
142
|
+
A cada 5 tasks ou release, atualize a seção Análise com totais agregados.
|
|
143
|
+
|
|
144
|
+
## Capturando informações do agente
|
|
145
|
+
|
|
146
|
+
Cada IDE expõe diferente:
|
|
147
|
+
|
|
148
|
+
**Antigravity:**
|
|
149
|
+
- Modelo aparece no header da conversa
|
|
150
|
+
- Tokens estimados em `?ax-debug` ou settings
|
|
151
|
+
|
|
152
|
+
**Claude Code:**
|
|
153
|
+
- `/cost` mostra tokens da sessão
|
|
154
|
+
- Modelo no rodapé
|
|
155
|
+
|
|
156
|
+
**Cursor:**
|
|
157
|
+
- Barra de status canto inferior direito
|
|
158
|
+
- Histórico de conversa tem detalhes por resposta
|
|
159
|
+
|
|
160
|
+
## Otimizações recomendadas
|
|
161
|
+
|
|
162
|
+
1. **Modelo certo para tarefa certa**
|
|
163
|
+
- Opus → design/blueprint/security review
|
|
164
|
+
- Sonnet → execução
|
|
165
|
+
- Gemini Flash → tasks simples, batch
|
|
166
|
+
2. **Reutilizar contexto** — múltiplas tasks na mesma sessão economiza re-leitura
|
|
167
|
+
3. **Revisar Blueprint antes de Tasks** — evita re-geração
|
|
168
|
+
4. **Agrupar tasks relacionadas** — contexto reaproveitado
|
|
169
|
+
5. **Ralph Loop alto = especificação ruim** — se task precisa >2 tentativas, refine BLUEPRINT.md
|
|
170
|
+
|
|
171
|
+
## Antipatterns
|
|
172
|
+
|
|
173
|
+
| AP | Antipattern | Por quê |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| AP-01 | Não rastrear telemetria | Sem dados para otimizar |
|
|
176
|
+
| AP-02 | Usar Opus para tasks triviais | Desperdício de custo |
|
|
177
|
+
| AP-03 | Ignorar Ralph Loop alto | Specs ruins se acumulam |
|
|
178
|
+
| AP-04 | Não auditar modelo (compliance) | Risco regulatório se houver |
|
|
179
|
+
|
|
180
|
+
## Dicas
|
|
181
|
+
|
|
182
|
+
- **Combine** com `dare-quality-telemetry` — esta rastreia uso de IA, aquela rastreia qualidade
|
|
183
|
+
- **Exporte** TELEMETRY.md para dashboard (Grafana, Notion, etc.) periodicamente
|
|
184
|
+
- **Trate custo como métrica** — adicione ao Ralph Loop como gate (>$Y/feature = revisar specs)
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
Esta skill é parte do DARE Method e está sob licença MIT.
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-fastapi-api
|
|
3
|
+
description: Padrões DARE para APIs REST em Python + FastAPI + Pydantic + uvicorn. Routers, dependency injection, Pydantic v2 schemas, async SQLAlchemy 2.0, autenticação OAuth2 + JWT, rate limit com slowapi, pytest + httpx, OpenAPI auto-gerado.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DARE FastAPI Skill
|
|
7
|
+
|
|
8
|
+
Você é um desenvolvedor sênior Python especialista em APIs REST com FastAPI. Seu objetivo é gerar código **assíncrono, fortemente tipado (Pydantic v2), com OpenAPI auto-gerado, auth/autz robustos**, seguindo Layered Design DARE.
|
|
9
|
+
|
|
10
|
+
## Quando usar
|
|
11
|
+
|
|
12
|
+
- Projeto FastAPI novo via DARE
|
|
13
|
+
- Adicionar feature em API FastAPI existente
|
|
14
|
+
- Migrar de Flask/Django para FastAPI
|
|
15
|
+
- Auditar projeto FastAPI para conformidade DARE
|
|
16
|
+
|
|
17
|
+
## Stack canônica
|
|
18
|
+
|
|
19
|
+
- **Python 3.11+** com type hints obrigatórios
|
|
20
|
+
- **FastAPI 0.115+** com async/await
|
|
21
|
+
- **Pydantic v2** para schemas
|
|
22
|
+
- **SQLAlchemy 2.0** async + **asyncpg** (PostgreSQL)
|
|
23
|
+
- **alembic** para migrations
|
|
24
|
+
- **passlib + argon2** para hash de senhas
|
|
25
|
+
- **python-jose** ou **PyJWT** para JWT
|
|
26
|
+
- **slowapi** para rate limiting
|
|
27
|
+
- **pytest + pytest-asyncio + httpx** para testes
|
|
28
|
+
- **ruff** para lint + format
|
|
29
|
+
- **mypy** para type checking
|
|
30
|
+
|
|
31
|
+
## Layered Design em FastAPI
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
app/
|
|
35
|
+
├── main.py ← FastAPI app + middlewares
|
|
36
|
+
├── core/
|
|
37
|
+
│ ├── config.py ← Settings via pydantic-settings
|
|
38
|
+
│ └── security.py ← hash, JWT
|
|
39
|
+
├── api/
|
|
40
|
+
│ ├── deps.py ← Depends() comuns
|
|
41
|
+
│ └── v1/
|
|
42
|
+
│ ├── users.py ← Handler (router)
|
|
43
|
+
│ └── auth.py
|
|
44
|
+
├── services/
|
|
45
|
+
│ └── register_user.py ← Service
|
|
46
|
+
├── repositories/
|
|
47
|
+
│ └── users.py ← Repository
|
|
48
|
+
├── models/ ← SQLAlchemy ORM
|
|
49
|
+
│ └── user.py
|
|
50
|
+
├── schemas/ ← Pydantic DTOs
|
|
51
|
+
│ ├── user.py
|
|
52
|
+
│ └── auth.py
|
|
53
|
+
└── tests/
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Routers (Handler)
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from fastapi import APIRouter, Depends, HTTPException, status
|
|
60
|
+
from app.api.deps import get_current_user
|
|
61
|
+
from app.schemas.user import UserCreate, UserOut
|
|
62
|
+
from app.services.register_user import RegisterUser, UserAlreadyExistsError
|
|
63
|
+
|
|
64
|
+
router = APIRouter(prefix="/users", tags=["users"])
|
|
65
|
+
|
|
66
|
+
@router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED)
|
|
67
|
+
async def create_user(
|
|
68
|
+
payload: UserCreate,
|
|
69
|
+
service: RegisterUser = Depends(),
|
|
70
|
+
_current: User = Depends(get_current_user),
|
|
71
|
+
):
|
|
72
|
+
try:
|
|
73
|
+
return await service.execute(payload)
|
|
74
|
+
except UserAlreadyExistsError:
|
|
75
|
+
raise HTTPException(status_code=409, detail="User already exists")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Regras:
|
|
79
|
+
- Apenas: valida via Pydantic → chama Service → retorna response_model
|
|
80
|
+
- NUNCA: SQLAlchemy direto, lógica de negócio
|
|
81
|
+
|
|
82
|
+
## Schemas (Pydantic v2)
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from pydantic import BaseModel, EmailStr, Field
|
|
86
|
+
from datetime import datetime
|
|
87
|
+
|
|
88
|
+
class UserCreate(BaseModel):
|
|
89
|
+
email: EmailStr
|
|
90
|
+
name: str = Field(min_length=1, max_length=255)
|
|
91
|
+
password: str = Field(min_length=12)
|
|
92
|
+
|
|
93
|
+
class UserOut(BaseModel):
|
|
94
|
+
id: int
|
|
95
|
+
email: EmailStr
|
|
96
|
+
name: str
|
|
97
|
+
created_at: datetime
|
|
98
|
+
|
|
99
|
+
model_config = {"from_attributes": True} # Pydantic v2 / ex-orm_mode
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Services
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from app.repositories.users import UsersRepository
|
|
106
|
+
from app.core.security import hash_password
|
|
107
|
+
from app.schemas.user import UserCreate
|
|
108
|
+
from app.models.user import User
|
|
109
|
+
|
|
110
|
+
class UserAlreadyExistsError(Exception): ...
|
|
111
|
+
|
|
112
|
+
class RegisterUser:
|
|
113
|
+
def __init__(self, repo: UsersRepository = Depends()):
|
|
114
|
+
self.repo = repo
|
|
115
|
+
|
|
116
|
+
async def execute(self, payload: UserCreate) -> User:
|
|
117
|
+
if await self.repo.exists_by_email(payload.email):
|
|
118
|
+
raise UserAlreadyExistsError()
|
|
119
|
+
return await self.repo.create(
|
|
120
|
+
email=payload.email,
|
|
121
|
+
name=payload.name,
|
|
122
|
+
password_hash=hash_password(payload.password),
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Repositories (SQLAlchemy async 2.0)
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from sqlalchemy import select
|
|
130
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
131
|
+
from fastapi import Depends
|
|
132
|
+
from app.api.deps import get_db
|
|
133
|
+
from app.models.user import User
|
|
134
|
+
|
|
135
|
+
class UsersRepository:
|
|
136
|
+
def __init__(self, db: AsyncSession = Depends(get_db)):
|
|
137
|
+
self.db = db
|
|
138
|
+
|
|
139
|
+
async def exists_by_email(self, email: str) -> bool:
|
|
140
|
+
result = await self.db.execute(select(User.id).where(User.email == email))
|
|
141
|
+
return result.scalar_one_or_none() is not None
|
|
142
|
+
|
|
143
|
+
async def create(self, *, email: str, name: str, password_hash: str) -> User:
|
|
144
|
+
user = User(email=email, name=name, password_hash=password_hash)
|
|
145
|
+
self.db.add(user)
|
|
146
|
+
await self.db.commit()
|
|
147
|
+
await self.db.refresh(user)
|
|
148
|
+
return user
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Models (SQLAlchemy)
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
155
|
+
from datetime import datetime
|
|
156
|
+
|
|
157
|
+
class Base(DeclarativeBase): ...
|
|
158
|
+
|
|
159
|
+
class User(Base):
|
|
160
|
+
__tablename__ = "users"
|
|
161
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
162
|
+
email: Mapped[str] = mapped_column(unique=True, index=True)
|
|
163
|
+
name: Mapped[str]
|
|
164
|
+
password_hash: Mapped[str]
|
|
165
|
+
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Auth (OAuth2 + JWT)
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
# app/core/security.py
|
|
172
|
+
from passlib.hash import argon2
|
|
173
|
+
from datetime import datetime, timedelta
|
|
174
|
+
from jose import jwt
|
|
175
|
+
from app.core.config import settings
|
|
176
|
+
|
|
177
|
+
def hash_password(p: str) -> str: return argon2.hash(p)
|
|
178
|
+
def verify_password(p: str, h: str) -> bool: return argon2.verify(p, h)
|
|
179
|
+
|
|
180
|
+
def create_access_token(sub: str) -> str:
|
|
181
|
+
expire = datetime.utcnow() + timedelta(minutes=15)
|
|
182
|
+
payload = {"sub": sub, "exp": expire}
|
|
183
|
+
return jwt.encode(payload, settings.JWT_SECRET, algorithm="HS256")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
# app/api/deps.py
|
|
188
|
+
from fastapi import Depends, HTTPException, status
|
|
189
|
+
from fastapi.security import OAuth2PasswordBearer
|
|
190
|
+
from jose import jwt, JWTError
|
|
191
|
+
from app.core.config import settings
|
|
192
|
+
|
|
193
|
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/v1/auth/login")
|
|
194
|
+
|
|
195
|
+
async def get_current_user(token: str = Depends(oauth2_scheme)) -> User:
|
|
196
|
+
try:
|
|
197
|
+
payload = jwt.decode(token, settings.JWT_SECRET, algorithms=["HS256"])
|
|
198
|
+
sub: str = payload.get("sub")
|
|
199
|
+
except JWTError:
|
|
200
|
+
raise HTTPException(status_code=401, detail="Invalid token")
|
|
201
|
+
# buscar user no DB ...
|
|
202
|
+
return user
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Rate limiting (slowapi)
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
from slowapi import Limiter
|
|
209
|
+
from slowapi.util import get_remote_address
|
|
210
|
+
|
|
211
|
+
limiter = Limiter(key_func=get_remote_address)
|
|
212
|
+
app.state.limiter = limiter
|
|
213
|
+
app.add_middleware(SlowAPIMiddleware)
|
|
214
|
+
|
|
215
|
+
@router.post("/login")
|
|
216
|
+
@limiter.limit("5/15minute")
|
|
217
|
+
async def login(request: Request, ...):
|
|
218
|
+
...
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## OpenAPI
|
|
222
|
+
|
|
223
|
+
FastAPI auto-gera em `/openapi.json`. Customize title/version/auth:
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
app = FastAPI(
|
|
227
|
+
title="Projeto API",
|
|
228
|
+
version="1.0",
|
|
229
|
+
openapi_url="/openapi.json",
|
|
230
|
+
docs_url="/docs",
|
|
231
|
+
redoc_url="/redoc",
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Settings (pydantic-settings)
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
# app/core/config.py
|
|
239
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
240
|
+
|
|
241
|
+
class Settings(BaseSettings):
|
|
242
|
+
DATABASE_URL: str
|
|
243
|
+
JWT_SECRET: str
|
|
244
|
+
JWT_EXPIRE_MINUTES: int = 15
|
|
245
|
+
model_config = SettingsConfigDict(env_file=".env")
|
|
246
|
+
|
|
247
|
+
settings = Settings()
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Testes
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
# tests/test_users.py
|
|
254
|
+
import pytest
|
|
255
|
+
from httpx import AsyncClient
|
|
256
|
+
|
|
257
|
+
@pytest.mark.asyncio
|
|
258
|
+
async def test_create_user(client: AsyncClient, admin_token: str):
|
|
259
|
+
response = await client.post(
|
|
260
|
+
"/v1/users",
|
|
261
|
+
json={"email": "jane@example.com", "name": "Jane", "password": "longsecret123"},
|
|
262
|
+
headers={"Authorization": f"Bearer {admin_token}"},
|
|
263
|
+
)
|
|
264
|
+
assert response.status_code == 201
|
|
265
|
+
assert response.json()["email"] == "jane@example.com"
|
|
266
|
+
|
|
267
|
+
@pytest.mark.asyncio
|
|
268
|
+
async def test_duplicate_email(client: AsyncClient, admin_token: str):
|
|
269
|
+
# cria primeiro
|
|
270
|
+
await client.post("/v1/users", json={...}, headers={...})
|
|
271
|
+
# tenta de novo
|
|
272
|
+
response = await client.post("/v1/users", json={...}, headers={...})
|
|
273
|
+
assert response.status_code == 409
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Antipatterns
|
|
277
|
+
|
|
278
|
+
| AP | Antipattern | Correção |
|
|
279
|
+
|---|---|---|
|
|
280
|
+
| AP-01 | SQLAlchemy direto no router | Repository injetado via Depends |
|
|
281
|
+
| AP-02 | Validação manual no router | Pydantic schema |
|
|
282
|
+
| AP-03 | Lógica no router | Service |
|
|
283
|
+
| AP-04 | `return user` (ORM) sem response_model | `response_model=UserOut` |
|
|
284
|
+
| AP-05 | Secret hardcoded | `pydantic-settings` + `.env` |
|
|
285
|
+
| AP-06 | Login sem rate limit | `@limiter.limit("5/15minute")` |
|
|
286
|
+
| AP-07 | `password=user.password` em response | `response_model=UserOut` sem password |
|
|
287
|
+
| AP-08 | Sem `from_attributes=True` | response_model não converte ORM |
|
|
288
|
+
|
|
289
|
+
## Segurança
|
|
290
|
+
|
|
291
|
+
- Senhas: `argon2.hash()` (passlib)
|
|
292
|
+
- JWT: HS256 com `JWT_SECRET ≥ 32 bytes`, ou RS256 com par de chaves
|
|
293
|
+
- Headers: middleware com HSTS, X-Frame-Options, CSP
|
|
294
|
+
- CORS específico, nunca `*`
|
|
295
|
+
- Rate limit em login + APIs públicas
|
|
296
|
+
- Refresh token com rotação
|
|
297
|
+
|
|
298
|
+
## CI
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
ruff check .
|
|
302
|
+
ruff format --check .
|
|
303
|
+
mypy app
|
|
304
|
+
pytest --cov=app --cov-fail-under=80
|
|
305
|
+
pip-audit
|
|
306
|
+
alembic upgrade head --sql > /dev/null # valida migrations
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Como aplicar
|
|
310
|
+
|
|
311
|
+
### Passo 1: Audit
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
grep -rn "db\.execute\|db\.query" app/api/ # AP-01
|
|
315
|
+
grep -rn "request\.json()" app/api/ # AP-02
|
|
316
|
+
grep -rn "JWT_SECRET\s*=\s*['\"]" app/ # AP-05
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Passo 2: Migrar para Pydantic schemas
|
|
320
|
+
|
|
321
|
+
Para cada `request.json()` ou validação inline → schema Pydantic.
|
|
322
|
+
|
|
323
|
+
### Passo 3: Extrair Services
|
|
324
|
+
|
|
325
|
+
Lógica > 5 linhas no router → Service injetável.
|
|
326
|
+
|
|
327
|
+
### Passo 4: Adicionar Repositories
|
|
328
|
+
|
|
329
|
+
Encapsular SQLAlchemy. Router chama Service via Depends, Service chama Repository.
|
|
330
|
+
|
|
331
|
+
### Passo 5: Configurar slowapi + auth
|
|
332
|
+
|
|
333
|
+
`app.add_middleware(SlowAPIMiddleware)` global + `@limiter.limit` em login.
|
|
334
|
+
|
|
335
|
+
## Dicas
|
|
336
|
+
|
|
337
|
+
- **Combine** com `dare-docker` (Python 3.11-slim, não-root, multi-stage)
|
|
338
|
+
- **Use** `dare-llm-integration` se houver Gemini/Claude (FastAPI + httpx async)
|
|
339
|
+
- **Para realtime**, FastAPI tem `WebSocket` nativo + `sse-starlette`
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
Esta skill é parte do DARE Method e está sob licença MIT.
|