@dewtech/dare-cli 0.3.5 → 0.3.7
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/dist/utils/project-generator.d.ts.map +1 -1
- package/dist/utils/project-generator.js +143 -72
- package/dist/utils/project-generator.js.map +1 -1
- package/dist/utils/templates.d.ts +1 -1
- package/dist/utils/templates.d.ts.map +1 -1
- package/dist/utils/templates.js +92 -98
- package/dist/utils/templates.js.map +1 -1
- package/package.json +8 -6
- package/templates/backend/node-nestjs/.env.example +9 -0
- package/templates/backend/node-nestjs/nest-cli.json +8 -0
- package/templates/backend/node-nestjs/package.json +50 -0
- package/templates/backend/node-nestjs/src/app.controller.ts +12 -0
- package/templates/backend/node-nestjs/src/app.module.ts +15 -0
- package/templates/backend/node-nestjs/src/app.service.ts +8 -0
- package/templates/backend/node-nestjs/src/main.ts +24 -0
- package/templates/backend/node-nestjs/tsconfig.json +21 -0
- package/templates/backend/php-laravel/.env.example +22 -0
- package/templates/backend/php-laravel/app/Http/Controllers/HealthController.php +15 -0
- package/templates/backend/php-laravel/composer.json +40 -0
- package/templates/backend/python-fastapi/.env.example +4 -0
- package/templates/backend/python-fastapi/app/api/router.py +8 -0
- package/templates/backend/python-fastapi/app/core/config.py +20 -0
- package/templates/backend/python-fastapi/main.py +35 -0
- package/templates/backend/python-fastapi/requirements.txt +13 -0
- package/templates/backend/rust-axum/.env.example +3 -0
- package/templates/backend/rust-axum/Cargo.toml +23 -0
- package/templates/backend/rust-axum/src/errors.rs +30 -0
- package/templates/backend/rust-axum/src/main.rs +32 -0
- package/templates/backend/rust-axum/src/routes.rs +6 -0
- package/templates/frontend/react/index.html +12 -0
- package/templates/frontend/react/package.json +35 -0
- package/templates/frontend/react/src/App.tsx +25 -0
- package/templates/frontend/react/src/main.tsx +9 -0
- package/templates/frontend/vue/package.json +32 -0
- package/templates/frontend/vue/src/App.vue +7 -0
- package/templates/frontend/vue/src/main.ts +10 -0
- package/templates/frontend/vue/src/router/index.ts +14 -0
- package/templates/frontend/vue/src/views/HomeView.vue +6 -0
- package/templates/ide/antigravity/.agents/skills/dare-blueprint/SKILL.md +224 -0
- package/templates/ide/antigravity/.agents/skills/dare-bugfix-design/SKILL.md +76 -0
- package/templates/ide/antigravity/.agents/skills/dare-design/SKILL.md +180 -0
- package/templates/ide/antigravity/.agents/skills/dare-execute/SKILL.md +264 -0
- package/templates/ide/antigravity/.agents/skills/dare-feature-design/SKILL.md +74 -0
- package/templates/ide/antigravity/.agents/skills/dare-tasks/SKILL.md +229 -0
- package/templates/ide/antigravity/templates/BLUEPRINT-template.md +53 -0
- package/templates/ide/antigravity/templates/DESIGN-template.md +34 -0
- package/templates/ide/antigravity/templates/TASK-SPEC-template.md +43 -0
- package/templates/ide/antigravity/templates/TASKS-template.md +26 -0
- package/templates/ide/antigravity/templates/TELEMETRY-template.md +125 -0
- package/templates/ide/cursor/.cursor/commands/execute-task.md +19 -0
- package/templates/ide/cursor/.cursor/commands/generate-blueprint.md +21 -0
- package/templates/ide/cursor/.cursor/commands/generate-bugfix-design.md +64 -0
- package/templates/ide/cursor/.cursor/commands/generate-design.md +18 -0
- package/templates/ide/cursor/.cursor/commands/generate-docker-compose.md +18 -0
- package/templates/ide/cursor/.cursor/commands/generate-dockerfile.md +17 -0
- package/templates/ide/cursor/.cursor/commands/generate-feature-design.md +64 -0
- package/templates/ide/cursor/.cursor/commands/generate-tasks.md +20 -0
- package/templates/ide/cursor/.cursor/commands/telemetry-report.md +42 -0
- package/templates/ide/cursor/.cursor/rules/skill-bugfix-design.mdc +51 -0
- package/templates/ide/cursor/.cursor/rules/skill-docker.mdc +33 -0
- package/templates/ide/cursor/.cursor/rules/skill-feature-design.mdc +43 -0
- package/templates/ide/cursor/.cursor/rules/skill-laravel-api.mdc +44 -0
- package/templates/ide/cursor/.cursor/rules/skill-security.mdc +57 -0
- package/templates/ide/cursor/.cursor/rules/skill-telemetry.mdc +156 -0
- package/templates/ide/cursor/templates/BLUEPRINT-template.md +53 -0
- package/templates/ide/cursor/templates/DESIGN-template.md +34 -0
- package/templates/ide/cursor/templates/TASK-SPEC-template.md +43 -0
- package/templates/ide/cursor/templates/TASKS-template.md +26 -0
- package/templates/ide/cursor/templates/TELEMETRY-template.md +125 -0
- package/templates/shared/docker-compose.yml +41 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}/api",
|
|
3
|
+
"description": "{{PROJECT_NAME}} API",
|
|
4
|
+
"type": "project",
|
|
5
|
+
"require": {
|
|
6
|
+
"php": "^8.2",
|
|
7
|
+
"laravel/framework": "^11.0",
|
|
8
|
+
"laravel/sanctum": "^4.0",
|
|
9
|
+
"tymon/jwt-auth": "^2.1"
|
|
10
|
+
},
|
|
11
|
+
"require-dev": {
|
|
12
|
+
"fakerphp/faker": "^1.23",
|
|
13
|
+
"laravel/pint": "^1.0",
|
|
14
|
+
"mockery/mockery": "^1.6",
|
|
15
|
+
"nunomaduro/collision": "^8.0",
|
|
16
|
+
"phpunit/phpunit": "^11.0",
|
|
17
|
+
"nunomaduro/larastan": "^2.0"
|
|
18
|
+
},
|
|
19
|
+
"autoload": {
|
|
20
|
+
"psr-4": {
|
|
21
|
+
"App\\": "app/",
|
|
22
|
+
"Database\\": "database/"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"autoload-dev": {
|
|
26
|
+
"psr-4": {
|
|
27
|
+
"Tests\\": "tests/"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"post-install-cmd": ["@php artisan key:generate --ansi"],
|
|
32
|
+
"test": "php artisan test",
|
|
33
|
+
"lint": "./vendor/bin/pint",
|
|
34
|
+
"analyse": "./vendor/bin/phpstan analyse"
|
|
35
|
+
},
|
|
36
|
+
"config": {
|
|
37
|
+
"optimize-autoloader": true,
|
|
38
|
+
"preferred-install": "dist"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from pydantic_settings import BaseSettings
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Settings(BaseSettings):
|
|
6
|
+
PROJECT_NAME: str = "{{PROJECT_NAME}}"
|
|
7
|
+
VERSION: str = "0.1.0"
|
|
8
|
+
ALLOWED_ORIGINS: List[str] = ["http://localhost:3000", "http://localhost:3001"]
|
|
9
|
+
|
|
10
|
+
DATABASE_URL: str = "postgresql+asyncpg://postgres:postgres@localhost:5432/{{PROJECT_NAME}}"
|
|
11
|
+
|
|
12
|
+
SECRET_KEY: str = "change-me-in-production"
|
|
13
|
+
ALGORITHM: str = "HS256"
|
|
14
|
+
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
|
15
|
+
|
|
16
|
+
class Config:
|
|
17
|
+
env_file = ".env"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
settings = Settings()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from fastapi import FastAPI
|
|
2
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
3
|
+
from contextlib import asynccontextmanager
|
|
4
|
+
|
|
5
|
+
from app.core.config import settings
|
|
6
|
+
from app.api.router import api_router
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@asynccontextmanager
|
|
10
|
+
async def lifespan(app: FastAPI):
|
|
11
|
+
# Startup
|
|
12
|
+
yield
|
|
13
|
+
# Shutdown
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
app = FastAPI(
|
|
17
|
+
title=settings.PROJECT_NAME,
|
|
18
|
+
version=settings.VERSION,
|
|
19
|
+
lifespan=lifespan,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
app.add_middleware(
|
|
23
|
+
CORSMiddleware,
|
|
24
|
+
allow_origins=settings.ALLOWED_ORIGINS,
|
|
25
|
+
allow_credentials=True,
|
|
26
|
+
allow_methods=["*"],
|
|
27
|
+
allow_headers=["*"],
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
app.include_router(api_router, prefix="/api")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@app.get("/health")
|
|
34
|
+
async def health() -> dict:
|
|
35
|
+
return {"status": "ok"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
fastapi>=0.115.0
|
|
2
|
+
uvicorn[standard]>=0.30.0
|
|
3
|
+
pydantic>=2.0.0
|
|
4
|
+
pydantic-settings>=2.0.0
|
|
5
|
+
sqlalchemy[asyncio]>=2.0.0
|
|
6
|
+
asyncpg>=0.29.0
|
|
7
|
+
alembic>=1.13.0
|
|
8
|
+
python-jose[cryptography]>=3.3.0
|
|
9
|
+
passlib[bcrypt]>=1.7.4
|
|
10
|
+
python-multipart>=0.0.9
|
|
11
|
+
httpx>=0.27.0
|
|
12
|
+
pytest>=8.0.0
|
|
13
|
+
pytest-asyncio>=0.23.0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "{{PROJECT_NAME}}"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
|
|
6
|
+
[dependencies]
|
|
7
|
+
axum = { version = "0.7", features = ["macros"] }
|
|
8
|
+
tokio = { version = "1", features = ["full"] }
|
|
9
|
+
tower = "0.4"
|
|
10
|
+
tower-http = { version = "0.5", features = ["cors", "trace"] }
|
|
11
|
+
serde = { version = "1", features = ["derive"] }
|
|
12
|
+
serde_json = "1"
|
|
13
|
+
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio", "uuid", "chrono"] }
|
|
14
|
+
uuid = { version = "1", features = ["v4", "serde"] }
|
|
15
|
+
chrono = { version = "0.4", features = ["serde"] }
|
|
16
|
+
anyhow = "1"
|
|
17
|
+
thiserror = "1"
|
|
18
|
+
tracing = "0.1"
|
|
19
|
+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
20
|
+
dotenvy = "0.15"
|
|
21
|
+
|
|
22
|
+
[dev-dependencies]
|
|
23
|
+
axum-test = "14"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
use axum::{http::StatusCode, response::IntoResponse, Json};
|
|
2
|
+
use serde_json::json;
|
|
3
|
+
use thiserror::Error;
|
|
4
|
+
|
|
5
|
+
#[derive(Error, Debug)]
|
|
6
|
+
pub enum AppError {
|
|
7
|
+
#[error("Not found: {0}")]
|
|
8
|
+
NotFound(String),
|
|
9
|
+
|
|
10
|
+
#[error("Unauthorized")]
|
|
11
|
+
Unauthorized,
|
|
12
|
+
|
|
13
|
+
#[error("Internal server error")]
|
|
14
|
+
Internal(#[from] anyhow::Error),
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl IntoResponse for AppError {
|
|
18
|
+
fn into_response(self) -> axum::response::Response {
|
|
19
|
+
let (status, message) = match &self {
|
|
20
|
+
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
|
|
21
|
+
AppError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized".to_string()),
|
|
22
|
+
AppError::Internal(_) => (
|
|
23
|
+
StatusCode::INTERNAL_SERVER_ERROR,
|
|
24
|
+
"Internal server error".to_string(),
|
|
25
|
+
),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
(status, Json(json!({ "error": message }))).into_response()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
mod routes;
|
|
2
|
+
mod errors;
|
|
3
|
+
|
|
4
|
+
use axum::{routing::get, Router};
|
|
5
|
+
use tower_http::cors::CorsLayer;
|
|
6
|
+
use tower_http::trace::TraceLayer;
|
|
7
|
+
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
|
8
|
+
|
|
9
|
+
#[tokio::main]
|
|
10
|
+
async fn main() {
|
|
11
|
+
dotenvy::dotenv().ok();
|
|
12
|
+
|
|
13
|
+
tracing_subscriber::registry()
|
|
14
|
+
.with(tracing_subscriber::EnvFilter::new(
|
|
15
|
+
std::env::var("RUST_LOG").unwrap_or_else(|_| "info".into()),
|
|
16
|
+
))
|
|
17
|
+
.with(tracing_subscriber::fmt::layer())
|
|
18
|
+
.init();
|
|
19
|
+
|
|
20
|
+
let app = Router::new()
|
|
21
|
+
.route("/health", get(routes::health))
|
|
22
|
+
.layer(CorsLayer::permissive())
|
|
23
|
+
.layer(TraceLayer::new_for_http());
|
|
24
|
+
|
|
25
|
+
let port = std::env::var("PORT").unwrap_or_else(|_| "3000".to_string());
|
|
26
|
+
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}"))
|
|
27
|
+
.await
|
|
28
|
+
.unwrap();
|
|
29
|
+
|
|
30
|
+
tracing::info!("Listening on {}", listener.local_addr().unwrap());
|
|
31
|
+
axum::serve(listener, app).await.unwrap();
|
|
32
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{PROJECT_NAME}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "tsc && vite build",
|
|
8
|
+
"preview": "vite preview",
|
|
9
|
+
"test": "vitest",
|
|
10
|
+
"lint": "eslint src --ext .ts,.tsx"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"react": "^18.3.0",
|
|
14
|
+
"react-dom": "^18.3.0",
|
|
15
|
+
"react-router-dom": "^6.26.0",
|
|
16
|
+
"@tanstack/react-query": "^5.0.0",
|
|
17
|
+
"zustand": "^4.5.0",
|
|
18
|
+
"axios": "^1.7.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/react": "^18.3.0",
|
|
22
|
+
"@types/react-dom": "^18.3.0",
|
|
23
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
24
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
25
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
26
|
+
"eslint": "^8.0.0",
|
|
27
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
28
|
+
"eslint-plugin-react-refresh": "^0.4.0",
|
|
29
|
+
"typescript": "^5.0.0",
|
|
30
|
+
"vite": "^5.4.0",
|
|
31
|
+
"vitest": "^1.0.0",
|
|
32
|
+
"@testing-library/react": "^16.0.0",
|
|
33
|
+
"@testing-library/jest-dom": "^6.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
2
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
const queryClient = new QueryClient();
|
|
5
|
+
|
|
6
|
+
function Home() {
|
|
7
|
+
return (
|
|
8
|
+
<div>
|
|
9
|
+
<h1>{{PROJECT_NAME}}</h1>
|
|
10
|
+
<p>DARE Framework — React App</p>
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function App() {
|
|
16
|
+
return (
|
|
17
|
+
<QueryClientProvider client={queryClient}>
|
|
18
|
+
<BrowserRouter>
|
|
19
|
+
<Routes>
|
|
20
|
+
<Route path="/" element={<Home />} />
|
|
21
|
+
</Routes>
|
|
22
|
+
</BrowserRouter>
|
|
23
|
+
</QueryClientProvider>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vue-tsc && vite build",
|
|
8
|
+
"preview": "vite preview",
|
|
9
|
+
"test": "vitest",
|
|
10
|
+
"lint": "eslint src --ext .ts,.vue"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"vue": "^3.5.0",
|
|
14
|
+
"vue-router": "^4.4.0",
|
|
15
|
+
"pinia": "^2.2.0",
|
|
16
|
+
"axios": "^1.7.0",
|
|
17
|
+
"@vueuse/core": "^11.0.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@vitejs/plugin-vue": "^5.1.0",
|
|
21
|
+
"@vue/test-utils": "^2.4.0",
|
|
22
|
+
"@vue/tsconfig": "^0.5.0",
|
|
23
|
+
"typescript": "^5.0.0",
|
|
24
|
+
"vite": "^5.4.0",
|
|
25
|
+
"vitest": "^1.0.0",
|
|
26
|
+
"vue-tsc": "^2.0.0",
|
|
27
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
28
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
29
|
+
"eslint": "^8.0.0",
|
|
30
|
+
"eslint-plugin-vue": "^9.0.0"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createRouter, createWebHistory } from 'vue-router';
|
|
2
|
+
|
|
3
|
+
const router = createRouter({
|
|
4
|
+
history: createWebHistory(import.meta.env.BASE_URL),
|
|
5
|
+
routes: [
|
|
6
|
+
{
|
|
7
|
+
path: '/',
|
|
8
|
+
name: 'home',
|
|
9
|
+
component: () => import('../views/HomeView.vue'),
|
|
10
|
+
},
|
|
11
|
+
],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export default router;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dare-blueprint
|
|
3
|
+
description: Gera um Task List estruturado a partir do Design aprovado. Use quando o usuário aprovar o DESIGN.md. Cria um documento BLUEPRINT.md com arquitetura, endpoints, modelo de dados e plano de execução.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DARE Blueprint Skill
|
|
7
|
+
|
|
8
|
+
Você é um arquiteto de software especializado em design de APIs e sistemas. Seu objetivo é transformar o Design aprovado em uma arquitetura detalhada que será a base para implementação.
|
|
9
|
+
|
|
10
|
+
## Quando usar esta skill
|
|
11
|
+
|
|
12
|
+
- Design.md foi aprovado pelo usuário
|
|
13
|
+
- Precisa-se detalhar a arquitetura técnica
|
|
14
|
+
- Necessário documentar endpoints e modelos
|
|
15
|
+
- Segunda fase do Método DARE
|
|
16
|
+
|
|
17
|
+
## Como usar
|
|
18
|
+
|
|
19
|
+
### Passo 1: Ler o Design Aprovado
|
|
20
|
+
Leia o arquivo `DARE/DESIGN.md` que foi aprovado. Extraia:
|
|
21
|
+
- Stack técnica
|
|
22
|
+
- Funcionalidades principais
|
|
23
|
+
- Requisitos não-funcionais
|
|
24
|
+
- Restrições
|
|
25
|
+
|
|
26
|
+
### Passo 2: Analisar Contexto
|
|
27
|
+
Leia os arquivos de contexto:
|
|
28
|
+
- `.agents/rules/dare-workflow.md` (ou `.cursorrules` se Cursor)
|
|
29
|
+
- Exemplos em `examples/`
|
|
30
|
+
- Templates em `templates/`
|
|
31
|
+
|
|
32
|
+
### Passo 3: Integrar Segurança
|
|
33
|
+
Consulte `skill-security` para:
|
|
34
|
+
- Autenticação/Autorização
|
|
35
|
+
- Validação de entrada
|
|
36
|
+
- Criptografia
|
|
37
|
+
- Proteção contra vulnerabilidades OWASP
|
|
38
|
+
|
|
39
|
+
### Passo 4: Gerar a Arquitetura
|
|
40
|
+
Crie um documento `DARE/BLUEPRINT.md` com a seguinte estrutura:
|
|
41
|
+
|
|
42
|
+
```markdown
|
|
43
|
+
# Blueprint: [Nome do Projeto]
|
|
44
|
+
|
|
45
|
+
## Visão Geral da Arquitetura
|
|
46
|
+
[Descrição da arquitetura escolhida: Monolito, Microserviços, Hexagonal, etc]
|
|
47
|
+
|
|
48
|
+
## Segurança (OWASP)
|
|
49
|
+
### Autenticação e Autorização
|
|
50
|
+
- Método: JWT com RS256
|
|
51
|
+
- Armazenamento: Bearer token no header
|
|
52
|
+
- Validação: Middleware em todos os endpoints protegidos
|
|
53
|
+
|
|
54
|
+
### Proteção de Dados
|
|
55
|
+
- Senhas: Bcrypt com salt
|
|
56
|
+
- Dados sensíveis: Encriptados em repouso
|
|
57
|
+
- Transmissão: HTTPS obrigatório
|
|
58
|
+
|
|
59
|
+
### Validação
|
|
60
|
+
- Input: Whitelist de valores permitidos
|
|
61
|
+
- Output: Escape de caracteres especiais
|
|
62
|
+
- Rate Limiting: 5 req/min por IP
|
|
63
|
+
|
|
64
|
+
## Modelo de Dados
|
|
65
|
+
### Tabela: users
|
|
66
|
+
| Campo | Tipo | Restrições |
|
|
67
|
+
|-------|------|-----------|
|
|
68
|
+
| id | UUID | PK |
|
|
69
|
+
| email | VARCHAR(255) | UNIQUE, NOT NULL |
|
|
70
|
+
| password_hash | VARCHAR(255) | NOT NULL (Bcrypt) |
|
|
71
|
+
| name | VARCHAR(255) | NOT NULL |
|
|
72
|
+
| is_active | BOOLEAN | DEFAULT true |
|
|
73
|
+
| created_at | TIMESTAMP | DEFAULT NOW() |
|
|
74
|
+
| updated_at | TIMESTAMP | DEFAULT NOW() |
|
|
75
|
+
|
|
76
|
+
### Tabela: refresh_tokens
|
|
77
|
+
| Campo | Tipo | Restrições |
|
|
78
|
+
|-------|------|-----------|
|
|
79
|
+
| id | UUID | PK |
|
|
80
|
+
| user_id | UUID | FK users.id |
|
|
81
|
+
| token | VARCHAR(500) | UNIQUE |
|
|
82
|
+
| expires_at | TIMESTAMP | NOT NULL |
|
|
83
|
+
| revoked_at | TIMESTAMP | NULL |
|
|
84
|
+
| created_at | TIMESTAMP | DEFAULT NOW() |
|
|
85
|
+
|
|
86
|
+
## Endpoints da API
|
|
87
|
+
|
|
88
|
+
| Método | Endpoint | Autenticação | Descrição |
|
|
89
|
+
|--------|----------|--------------|-----------|
|
|
90
|
+
| POST | /api/auth/register | Não | Registrar novo usuário |
|
|
91
|
+
| POST | /api/auth/login | Não | Login e obter JWT |
|
|
92
|
+
| POST | /api/auth/refresh | Não | Renovar JWT com refresh token |
|
|
93
|
+
| POST | /api/auth/logout | JWT | Logout e revogar tokens |
|
|
94
|
+
| GET | /api/users/me | JWT | Obter dados do usuário logado |
|
|
95
|
+
|
|
96
|
+
### Detalhes dos Endpoints
|
|
97
|
+
|
|
98
|
+
#### POST /api/auth/register
|
|
99
|
+
**Request:**
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"email": "user@example.com",
|
|
103
|
+
"password": "SecurePass123!",
|
|
104
|
+
"name": "John Doe"
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Response (201):**
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"id": "uuid",
|
|
112
|
+
"email": "user@example.com",
|
|
113
|
+
"name": "John Doe",
|
|
114
|
+
"created_at": "2026-04-14T10:00:00Z"
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Validações:**
|
|
119
|
+
- Email válido e único
|
|
120
|
+
- Senha: mínimo 8 caracteres, 1 maiúscula, 1 número, 1 caractere especial
|
|
121
|
+
- Name: mínimo 3 caracteres
|
|
122
|
+
|
|
123
|
+
## Estrutura de Diretórios
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
projeto/
|
|
127
|
+
├── app/
|
|
128
|
+
│ ├── Models/
|
|
129
|
+
│ │ ├── User.php
|
|
130
|
+
│ │ └── RefreshToken.php
|
|
131
|
+
│ ├── Http/
|
|
132
|
+
│ │ ├── Controllers/
|
|
133
|
+
│ │ │ └── AuthController.php
|
|
134
|
+
│ │ ├── Requests/
|
|
135
|
+
│ │ │ ├── RegisterRequest.php
|
|
136
|
+
│ │ │ └── LoginRequest.php
|
|
137
|
+
│ │ └── Resources/
|
|
138
|
+
│ │ └── UserResource.php
|
|
139
|
+
│ ├── Services/
|
|
140
|
+
│ │ └── AuthService.php
|
|
141
|
+
│ └── Exceptions/
|
|
142
|
+
│ └── AuthException.php
|
|
143
|
+
├── database/
|
|
144
|
+
│ └── migrations/
|
|
145
|
+
│ ├── create_users_table.php
|
|
146
|
+
│ └── create_refresh_tokens_table.php
|
|
147
|
+
├── routes/
|
|
148
|
+
│ └── api.php
|
|
149
|
+
└── tests/
|
|
150
|
+
└── Feature/
|
|
151
|
+
└── AuthTest.php
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Plano de Execução
|
|
155
|
+
|
|
156
|
+
### Fase 1: Setup Inicial
|
|
157
|
+
- Criar migrations (users, refresh_tokens)
|
|
158
|
+
- Configurar autenticação JWT
|
|
159
|
+
- Setup de testes
|
|
160
|
+
|
|
161
|
+
### Fase 2: Autenticação
|
|
162
|
+
- Implementar RegisterController
|
|
163
|
+
- Implementar LoginController
|
|
164
|
+
- Implementar RefreshController
|
|
165
|
+
|
|
166
|
+
### Fase 3: Proteção
|
|
167
|
+
- Implementar Middleware de JWT
|
|
168
|
+
- Implementar Rate Limiting
|
|
169
|
+
- Implementar Logout
|
|
170
|
+
|
|
171
|
+
### Fase 4: Testes e Deploy
|
|
172
|
+
- Testes unitários
|
|
173
|
+
- Testes de integração
|
|
174
|
+
- Containerização com Docker
|
|
175
|
+
|
|
176
|
+
## Comandos de Setup
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Instalar dependências
|
|
180
|
+
composer install
|
|
181
|
+
|
|
182
|
+
# Criar arquivo .env
|
|
183
|
+
cp .env.example .env
|
|
184
|
+
php artisan key:generate
|
|
185
|
+
|
|
186
|
+
# Rodar migrations
|
|
187
|
+
php artisan migrate
|
|
188
|
+
|
|
189
|
+
# Gerar JWT secret
|
|
190
|
+
php artisan jwt:secret
|
|
191
|
+
|
|
192
|
+
# Rodar testes
|
|
193
|
+
php artisan test
|
|
194
|
+
|
|
195
|
+
# Iniciar servidor
|
|
196
|
+
php artisan serve
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Próximas Etapas
|
|
200
|
+
1. Revisar e aprovar este Blueprint
|
|
201
|
+
2. Executar `/generate-tasks DARE/BLUEPRINT.md`
|
|
202
|
+
3. Continuar com o Método DARE
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Passo 5: Pedir Aprovação
|
|
206
|
+
Após gerar o Blueprint, peça ao usuário:
|
|
207
|
+
- Revisar a arquitetura
|
|
208
|
+
- Aprovar endpoints e modelos
|
|
209
|
+
- Confirmar antes de continuar
|
|
210
|
+
|
|
211
|
+
## Boas Práticas
|
|
212
|
+
|
|
213
|
+
1. **Detalhado:** Inclua exemplos de request/response
|
|
214
|
+
2. **Seguro:** Sempre implemente proteções OWASP
|
|
215
|
+
3. **Escalável:** Pense em crescimento futuro
|
|
216
|
+
4. **Testável:** Estruture para facilitar testes
|
|
217
|
+
5. **Documentado:** Deixe claro para implementação
|
|
218
|
+
|
|
219
|
+
## Dicas para Melhor Resultado
|
|
220
|
+
|
|
221
|
+
- **Contexto:** Leia exemplos em `examples/` para manter padrões
|
|
222
|
+
- **Segurança:** Consulte `skill-security` para requisitos
|
|
223
|
+
- **Templates:** Use `templates/BLUEPRINT-template.md` como referência
|
|
224
|
+
- **Docker:** Considere incluir informações para containerização
|