devsquad 1.0.0 → 1.1.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/bin/devsquad.js +37 -11
- package/package.json +1 -1
- package/src/init.js +70 -26
- package/src/update.js +95 -0
- package/templates/.claude/skills/cicd/SKILL.md +46 -0
- package/templates/.claude/skills/cicd/backend-ci.md +114 -0
- package/templates/.claude/skills/cicd/frontend-ci.md +97 -0
- package/templates/.claude/skills/clickup/SKILL.md +63 -14
- package/templates/.claude/skills/docs/templates.md +203 -39
- package/templates/.claude/skills/figma/SKILL.md +125 -26
- package/templates/.claude/skills/nestjs/api-contracts.md +221 -0
- package/templates/.claude/skills/react/setup.md +61 -14
- package/templates/.claude/skills/testing/SKILL.md +78 -0
- package/templates/.claude/skills/testing/backend.md +161 -0
- package/templates/.claude/skills/testing/e2e.md +156 -0
- package/templates/.claude/skills/testing/frontend.md +138 -0
- package/templates/CLAUDE.md +7 -3
package/bin/devsquad.js
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseArgs } from 'node:util';
|
|
3
3
|
import { init } from '../src/init.js';
|
|
4
|
+
import { update } from '../src/update.js';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { join, dirname } from 'node:path';
|
|
4
8
|
|
|
5
|
-
const
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
11
|
+
|
|
12
|
+
const { positionals, values } = parseArgs({
|
|
6
13
|
args: process.argv.slice(2),
|
|
14
|
+
options: {
|
|
15
|
+
yes: { type: 'boolean', short: 'y', default: false },
|
|
16
|
+
version: { type: 'boolean', short: 'v', default: false },
|
|
17
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
18
|
+
},
|
|
7
19
|
strict: false,
|
|
8
20
|
allowPositionals: true,
|
|
9
21
|
});
|
|
@@ -19,24 +31,38 @@ function showHelp() {
|
|
|
19
31
|
██████╔╝███████╗ ╚████╔╝ ███████║╚██████╔╝╚██████╔╝██║ ██║██████╔╝
|
|
20
32
|
╚═════╝ ╚══════╝ ╚═══╝ ╚══════╝ ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝
|
|
21
33
|
|
|
22
|
-
Agente especializado em
|
|
34
|
+
v${pkg.version} — Agente especializado em sistemas profissionais
|
|
23
35
|
Stack: NestJS · React · React Native · Prisma · PostgreSQL · JWT
|
|
24
36
|
|
|
25
|
-
Comandos
|
|
26
|
-
npx devsquad init
|
|
37
|
+
Comandos:
|
|
38
|
+
npx devsquad init Instala o DevSquad no projeto atual
|
|
39
|
+
npx devsquad update Atualiza os arquivos do DevSquad
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
Opções:
|
|
42
|
+
-y, --yes Pula confirmações interativas
|
|
43
|
+
-v, --version Exibe a versão
|
|
44
|
+
-h, --help Exibe esta ajuda
|
|
30
45
|
`);
|
|
31
46
|
}
|
|
32
47
|
|
|
33
48
|
try {
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
} else {
|
|
49
|
+
if (values.version) {
|
|
50
|
+
console.log(`devsquad v${pkg.version}`);
|
|
51
|
+
} else if (values.help || !command) {
|
|
37
52
|
showHelp();
|
|
53
|
+
} else if (command === 'init') {
|
|
54
|
+
await init(process.cwd(), { yes: values.yes });
|
|
55
|
+
} else if (command === 'update') {
|
|
56
|
+
await update(process.cwd(), { yes: values.yes });
|
|
57
|
+
} else {
|
|
58
|
+
console.error(`\n Comando desconhecido: "${command}"\n Use --help para ver os comandos disponíveis.\n`);
|
|
59
|
+
process.exit(1);
|
|
38
60
|
}
|
|
39
61
|
} catch (err) {
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
if (err.name === 'ExitPromptError') {
|
|
63
|
+
console.log('\n Cancelado.\n');
|
|
64
|
+
} else {
|
|
65
|
+
console.error('\n Erro:', err.message);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
42
68
|
}
|
package/package.json
CHANGED
package/src/init.js
CHANGED
|
@@ -24,7 +24,54 @@ function fileExists(targetDir, relPath) {
|
|
|
24
24
|
return fs.existsSync(path.join(targetDir, relPath));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
function generateNextSteps() {
|
|
28
|
+
return `# Próximos passos com o DevSquad
|
|
29
|
+
|
|
30
|
+
Bem-vindo! O DevSquad está instalado e pronto para uso no Claude Code.
|
|
31
|
+
|
|
32
|
+
## Iniciar um novo projeto
|
|
33
|
+
|
|
34
|
+
Abra o Claude Code neste diretório e execute:
|
|
35
|
+
|
|
36
|
+
\`\`\`
|
|
37
|
+
/devsquad init
|
|
38
|
+
\`\`\`
|
|
39
|
+
|
|
40
|
+
O DevSquad vai fazer 10 perguntas e gerar a estrutura completa do projeto.
|
|
41
|
+
|
|
42
|
+
## Comandos disponíveis
|
|
43
|
+
|
|
44
|
+
| Comando | O que faz |
|
|
45
|
+
|---------|-----------|
|
|
46
|
+
| \`/devsquad init\` | Onboarding completo — perguntas + estrutura do projeto |
|
|
47
|
+
| \`/devsquad backend\` | Setup NestJS + Prisma + PostgreSQL + JWT |
|
|
48
|
+
| \`/devsquad frontend\` | Setup React + TypeScript + TailwindCSS |
|
|
49
|
+
| \`/devsquad mobile\` | Setup React Native + Expo + NativeWind |
|
|
50
|
+
| \`/devsquad database\` | Modelagem Prisma + migrations + seed |
|
|
51
|
+
| \`/devsquad git\` | Git Flow + Conventional Commits + Husky |
|
|
52
|
+
| \`/devsquad security\` | Checklist OWASP Top 10 |
|
|
53
|
+
| \`/devsquad testing\` | Jest + Vitest + Playwright |
|
|
54
|
+
| \`/devsquad cicd\` | GitHub Actions (backend + frontend + mobile) |
|
|
55
|
+
| \`/devsquad clickup\` | Estrutura de projeto + tasks no ClickUp |
|
|
56
|
+
| \`/devsquad postman\` | Collections e environments de API |
|
|
57
|
+
| \`/devsquad docs\` | README, ARCHITECTURE, CONTRIBUTING, SECURITY |
|
|
58
|
+
| \`/devsquad figma\` | Tokens de design → Tailwind + handoff |
|
|
59
|
+
|
|
60
|
+
## Atualizar o DevSquad
|
|
61
|
+
|
|
62
|
+
\`\`\`bash
|
|
63
|
+
npx devsquad update
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
Pode apagar este arquivo após ler.
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function init(targetDir, options = {}) {
|
|
73
|
+
const { yes = false } = options;
|
|
74
|
+
|
|
28
75
|
console.log(`
|
|
29
76
|
██████╗ ███████╗██╗ ██╗███████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗
|
|
30
77
|
██╔══██╗██╔════╝██║ ██║██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔══██╗
|
|
@@ -39,7 +86,7 @@ export async function init(targetDir) {
|
|
|
39
86
|
|
|
40
87
|
// Verificar se já existe instalação
|
|
41
88
|
const alreadyInstalled = fileExists(targetDir, 'CLAUDE.md') && fileExists(targetDir, '.claude');
|
|
42
|
-
if (alreadyInstalled) {
|
|
89
|
+
if (alreadyInstalled && !yes) {
|
|
43
90
|
console.log(' ⚠️ Detectamos que o DevSquad já pode estar instalado neste projeto.\n');
|
|
44
91
|
const overwrite = await confirm({
|
|
45
92
|
message: 'Deseja reinstalar e sobrescrever os arquivos existentes?',
|
|
@@ -49,7 +96,7 @@ export async function init(targetDir) {
|
|
|
49
96
|
console.log('\n Instalação cancelada. Seu projeto não foi modificado.\n');
|
|
50
97
|
return;
|
|
51
98
|
}
|
|
52
|
-
} else {
|
|
99
|
+
} else if (!alreadyInstalled && !yes) {
|
|
53
100
|
const proceed = await confirm({
|
|
54
101
|
message: 'Instalar o DevSquad neste diretório?',
|
|
55
102
|
default: true,
|
|
@@ -61,26 +108,25 @@ export async function init(targetDir) {
|
|
|
61
108
|
}
|
|
62
109
|
|
|
63
110
|
// Selecionar IDE
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
111
|
+
let ide = 'other';
|
|
112
|
+
if (!yes) {
|
|
113
|
+
ide = await select({
|
|
114
|
+
message: 'Qual IDE você usa?',
|
|
115
|
+
choices: [
|
|
116
|
+
{ name: 'VS Code / Cursor', value: 'vscode' },
|
|
117
|
+
{ name: 'Outro / Nenhum', value: 'other' },
|
|
118
|
+
],
|
|
119
|
+
});
|
|
120
|
+
}
|
|
71
121
|
|
|
72
122
|
console.log('\n Instalando DevSquad...\n');
|
|
73
123
|
|
|
74
124
|
// Copiar CLAUDE.md
|
|
75
|
-
|
|
76
|
-
const claudeMdDest = path.join(targetDir, 'CLAUDE.md');
|
|
77
|
-
fs.copyFileSync(claudeMdSrc, claudeMdDest);
|
|
125
|
+
fs.copyFileSync(path.join(templatesDir, 'CLAUDE.md'), path.join(targetDir, 'CLAUDE.md'));
|
|
78
126
|
console.log(' ✅ CLAUDE.md');
|
|
79
127
|
|
|
80
128
|
// Copiar .claude/
|
|
81
|
-
|
|
82
|
-
const claudeDirDest = path.join(targetDir, '.claude');
|
|
83
|
-
copyDir(claudeDirSrc, claudeDirDest);
|
|
129
|
+
copyDir(path.join(templatesDir, '.claude'), path.join(targetDir, '.claude'));
|
|
84
130
|
console.log(' ✅ .claude/agents/');
|
|
85
131
|
console.log(' ✅ .claude/skills/');
|
|
86
132
|
|
|
@@ -98,21 +144,19 @@ export async function init(targetDir) {
|
|
|
98
144
|
}
|
|
99
145
|
}
|
|
100
146
|
|
|
147
|
+
// Gerar NEXT_STEPS.md
|
|
148
|
+
fs.writeFileSync(path.join(targetDir, 'NEXT_STEPS.md'), generateNextSteps());
|
|
149
|
+
console.log(' ✅ NEXT_STEPS.md');
|
|
150
|
+
|
|
101
151
|
console.log(`
|
|
102
152
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
103
153
|
|
|
104
154
|
🚀 DevSquad instalado com sucesso!
|
|
105
155
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
• /devsquad backend → Setup NestJS + Prisma
|
|
111
|
-
• /devsquad frontend → Setup React + TailwindCSS
|
|
112
|
-
• /devsquad mobile → Setup React Native + Expo
|
|
113
|
-
• /devsquad git → Git Flow + Conventional Commits
|
|
114
|
-
• /devsquad database → Prisma + PostgreSQL
|
|
115
|
-
• /devsquad security → OWASP Top 10
|
|
156
|
+
Leia o NEXT_STEPS.md para começar.
|
|
157
|
+
|
|
158
|
+
Abra este projeto no Claude Code e execute:
|
|
159
|
+
/devsquad init
|
|
116
160
|
|
|
117
161
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
118
162
|
`);
|
package/src/update.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
import confirm from '@inquirer/confirm';
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const templatesDir = path.join(__dirname, '..', 'templates');
|
|
9
|
+
|
|
10
|
+
function copyDir(src, dest) {
|
|
11
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
12
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
13
|
+
const srcPath = path.join(src, entry.name);
|
|
14
|
+
const destPath = path.join(dest, entry.name);
|
|
15
|
+
if (entry.isDirectory()) {
|
|
16
|
+
copyDir(srcPath, destPath);
|
|
17
|
+
} else {
|
|
18
|
+
fs.copyFileSync(srcPath, destPath);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getInstalledVersion(targetDir) {
|
|
24
|
+
try {
|
|
25
|
+
const pkgPath = path.join(targetDir, 'node_modules', 'devsquad', 'package.json');
|
|
26
|
+
if (fs.existsSync(pkgPath)) {
|
|
27
|
+
return JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version;
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
// não instalado localmente
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getLatestVersion() {
|
|
36
|
+
try {
|
|
37
|
+
return execSync('npm show devsquad version', { encoding: 'utf8' }).trim();
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function update(targetDir) {
|
|
44
|
+
console.log('\n Verificando atualizações do DevSquad...\n');
|
|
45
|
+
|
|
46
|
+
const localVersion = getInstalledVersion(targetDir);
|
|
47
|
+
const latestVersion = getLatestVersion();
|
|
48
|
+
const currentPkg = JSON.parse(
|
|
49
|
+
fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
console.log(` Versão instalada: ${localVersion ?? currentPkg.version}`);
|
|
53
|
+
console.log(` Versão disponível: ${latestVersion ?? 'desconhecida'}\n`);
|
|
54
|
+
|
|
55
|
+
if (latestVersion && localVersion === latestVersion) {
|
|
56
|
+
console.log(' ✅ DevSquad já está na versão mais recente!\n');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const proceed = await confirm({
|
|
61
|
+
message: latestVersion
|
|
62
|
+
? `Atualizar para v${latestVersion}?`
|
|
63
|
+
: 'Atualizar os arquivos do DevSquad neste projeto?',
|
|
64
|
+
default: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!proceed) {
|
|
68
|
+
console.log('\n Atualização cancelada.\n');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log('\n Atualizando arquivos...\n');
|
|
73
|
+
|
|
74
|
+
// Atualizar CLAUDE.md
|
|
75
|
+
const claudeMdSrc = path.join(templatesDir, 'CLAUDE.md');
|
|
76
|
+
const claudeMdDest = path.join(targetDir, 'CLAUDE.md');
|
|
77
|
+
fs.copyFileSync(claudeMdSrc, claudeMdDest);
|
|
78
|
+
console.log(' ✅ CLAUDE.md');
|
|
79
|
+
|
|
80
|
+
// Atualizar .claude/agents/ e .claude/skills/
|
|
81
|
+
const claudeDirSrc = path.join(templatesDir, '.claude');
|
|
82
|
+
const claudeDirDest = path.join(targetDir, '.claude');
|
|
83
|
+
copyDir(claudeDirSrc, claudeDirDest);
|
|
84
|
+
console.log(' ✅ .claude/agents/');
|
|
85
|
+
console.log(' ✅ .claude/skills/');
|
|
86
|
+
|
|
87
|
+
console.log(`
|
|
88
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
89
|
+
✅ DevSquad atualizado com sucesso!
|
|
90
|
+
|
|
91
|
+
Suas configurações personalizadas (agent-memory,
|
|
92
|
+
settings.local.json) não foram modificadas.
|
|
93
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
94
|
+
`);
|
|
95
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cicd
|
|
3
|
+
description: CI/CD com GitHub Actions para NestJS + React + React Native. Use quando o desenvolvedor precisar configurar pipelines de integração contínua, deploy automatizado, validação de PRs ou publicação de builds.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CI/CD — GitHub Actions
|
|
7
|
+
|
|
8
|
+
Stack: GitHub Actions · Docker · Railway / Render / Fly.io (backend) · Vercel / Netlify (frontend) · EAS (mobile)
|
|
9
|
+
|
|
10
|
+
## Estratégia de pipelines
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Push para feature/ → lint + testes unitários (rápido, < 2min)
|
|
14
|
+
PR para develop → lint + testes + build + cobertura
|
|
15
|
+
PR para main → tudo acima + testes e2e
|
|
16
|
+
Merge em main → deploy automático (produção)
|
|
17
|
+
Merge em develop → deploy automático (staging)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Arquivos desta skill
|
|
21
|
+
|
|
22
|
+
- **backend-ci.md** — Pipeline NestJS: lint, testes, migrations, deploy
|
|
23
|
+
- **frontend-ci.md** — Pipeline React: lint, testes, build, deploy Vercel
|
|
24
|
+
- **mobile-ci.md** — Pipeline Expo: lint, build EAS, distribuição
|
|
25
|
+
- **pr-checks.md** — Validações obrigatórias em todo PR
|
|
26
|
+
|
|
27
|
+
## Setup inicial
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
mkdir -p .github/workflows
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Secrets necessários (GitHub → Settings → Secrets)
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
DATABASE_URL ← banco de staging/produção
|
|
37
|
+
JWT_SECRET ← segredo JWT
|
|
38
|
+
JWT_REFRESH_SECRET ← segredo refresh
|
|
39
|
+
RAILWAY_TOKEN ← deploy backend (ou RENDER_API_KEY)
|
|
40
|
+
VERCEL_TOKEN ← deploy frontend
|
|
41
|
+
VERCEL_ORG_ID ← organização Vercel
|
|
42
|
+
VERCEL_PROJECT_ID ← projeto Vercel
|
|
43
|
+
EXPO_TOKEN ← build mobile EAS
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Leia os arquivos de detalhe para implementar cada pipeline.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# CI/CD — Backend NestJS
|
|
2
|
+
|
|
3
|
+
## .github/workflows/backend.yml
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: Backend CI
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main, develop]
|
|
11
|
+
paths: ['backend/**', '.github/workflows/backend.yml']
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: [main, develop]
|
|
14
|
+
paths: ['backend/**']
|
|
15
|
+
|
|
16
|
+
defaults:
|
|
17
|
+
run:
|
|
18
|
+
working-directory: backend
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
lint-and-test:
|
|
22
|
+
name: Lint + Testes
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
|
|
25
|
+
services:
|
|
26
|
+
postgres:
|
|
27
|
+
image: postgres:16-alpine
|
|
28
|
+
env:
|
|
29
|
+
POSTGRES_USER: test
|
|
30
|
+
POSTGRES_PASSWORD: test
|
|
31
|
+
POSTGRES_DB: app_test
|
|
32
|
+
ports: ['5432:5432']
|
|
33
|
+
options: >-
|
|
34
|
+
--health-cmd pg_isready
|
|
35
|
+
--health-interval 10s
|
|
36
|
+
--health-timeout 5s
|
|
37
|
+
--health-retries 5
|
|
38
|
+
|
|
39
|
+
env:
|
|
40
|
+
DATABASE_URL: postgresql://test:test@localhost:5432/app_test
|
|
41
|
+
JWT_SECRET: ci-secret-do-not-use-in-prod
|
|
42
|
+
JWT_REFRESH_SECRET: ci-refresh-secret-do-not-use-in-prod
|
|
43
|
+
NODE_ENV: test
|
|
44
|
+
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
|
|
48
|
+
- uses: actions/setup-node@v4
|
|
49
|
+
with:
|
|
50
|
+
node-version: '20'
|
|
51
|
+
cache: 'npm'
|
|
52
|
+
cache-dependency-path: backend/package-lock.json
|
|
53
|
+
|
|
54
|
+
- name: Instalar dependências
|
|
55
|
+
run: npm ci
|
|
56
|
+
|
|
57
|
+
- name: Lint
|
|
58
|
+
run: npm run lint
|
|
59
|
+
|
|
60
|
+
- name: Rodar migrations de teste
|
|
61
|
+
run: npx prisma migrate deploy
|
|
62
|
+
|
|
63
|
+
- name: Testes unitários
|
|
64
|
+
run: npm run test:cov
|
|
65
|
+
|
|
66
|
+
- name: Testes de integração (e2e)
|
|
67
|
+
run: npm run test:e2e
|
|
68
|
+
|
|
69
|
+
- name: Upload cobertura
|
|
70
|
+
uses: codecov/codecov-action@v4
|
|
71
|
+
with:
|
|
72
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
73
|
+
directory: backend/coverage
|
|
74
|
+
|
|
75
|
+
deploy-staging:
|
|
76
|
+
name: Deploy Staging
|
|
77
|
+
needs: lint-and-test
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
|
|
80
|
+
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/checkout@v4
|
|
83
|
+
|
|
84
|
+
- name: Deploy no Railway (staging)
|
|
85
|
+
uses: railway/railway-action@v2
|
|
86
|
+
with:
|
|
87
|
+
token: ${{ secrets.RAILWAY_TOKEN }}
|
|
88
|
+
service: backend-staging
|
|
89
|
+
|
|
90
|
+
deploy-production:
|
|
91
|
+
name: Deploy Produção
|
|
92
|
+
needs: lint-and-test
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
95
|
+
environment: production
|
|
96
|
+
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@v4
|
|
99
|
+
|
|
100
|
+
- name: Deploy no Railway (produção)
|
|
101
|
+
uses: railway/railway-action@v2
|
|
102
|
+
with:
|
|
103
|
+
token: ${{ secrets.RAILWAY_TOKEN }}
|
|
104
|
+
service: backend-production
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Checklist de CI backend
|
|
108
|
+
|
|
109
|
+
- [ ] Banco de teste isolado via service container
|
|
110
|
+
- [ ] Migrations rodam antes dos testes de integração
|
|
111
|
+
- [ ] Secrets reais NUNCA no código — apenas em GitHub Secrets
|
|
112
|
+
- [ ] Deploy de produção protegido por `environment: production` (aprovação manual)
|
|
113
|
+
- [ ] Cobertura enviada ao Codecov ou similar
|
|
114
|
+
- [ ] Cache de `node_modules` configurado para builds mais rápidos
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# CI/CD — Frontend React + Vercel
|
|
2
|
+
|
|
3
|
+
## .github/workflows/frontend.yml
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: Frontend CI
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main, develop]
|
|
11
|
+
paths: ['frontend/**', '.github/workflows/frontend.yml']
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: [main, develop]
|
|
14
|
+
paths: ['frontend/**']
|
|
15
|
+
|
|
16
|
+
defaults:
|
|
17
|
+
run:
|
|
18
|
+
working-directory: frontend
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
lint-test-build:
|
|
22
|
+
name: Lint + Testes + Build
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- uses: actions/setup-node@v4
|
|
29
|
+
with:
|
|
30
|
+
node-version: '20'
|
|
31
|
+
cache: 'npm'
|
|
32
|
+
cache-dependency-path: frontend/package-lock.json
|
|
33
|
+
|
|
34
|
+
- name: Instalar dependências
|
|
35
|
+
run: npm ci
|
|
36
|
+
|
|
37
|
+
- name: Lint
|
|
38
|
+
run: npm run lint
|
|
39
|
+
|
|
40
|
+
- name: Testes com cobertura
|
|
41
|
+
run: npm run test:run -- --coverage
|
|
42
|
+
|
|
43
|
+
- name: Build
|
|
44
|
+
run: npm run build
|
|
45
|
+
env:
|
|
46
|
+
VITE_API_URL: ${{ secrets.VITE_API_URL_STAGING }}
|
|
47
|
+
|
|
48
|
+
- name: Upload cobertura
|
|
49
|
+
uses: codecov/codecov-action@v4
|
|
50
|
+
with:
|
|
51
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
52
|
+
|
|
53
|
+
deploy-vercel:
|
|
54
|
+
name: Deploy Vercel
|
|
55
|
+
needs: lint-test-build
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
if: github.event_name == 'push'
|
|
58
|
+
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
|
|
62
|
+
- name: Deploy no Vercel
|
|
63
|
+
uses: amondnet/vercel-action@v25
|
|
64
|
+
with:
|
|
65
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
66
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
67
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
68
|
+
vercel-args: ${{ github.ref == 'refs/heads/main' && '--prod' || '' }}
|
|
69
|
+
working-directory: frontend
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Preview automático em PRs
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
# Adicionar ao job deploy-vercel para PRs
|
|
76
|
+
- name: Comentar URL de preview no PR
|
|
77
|
+
uses: actions/github-script@v7
|
|
78
|
+
if: github.event_name == 'pull_request'
|
|
79
|
+
with:
|
|
80
|
+
script: |
|
|
81
|
+
github.rest.issues.createComment({
|
|
82
|
+
issue_number: context.issue.number,
|
|
83
|
+
owner: context.repo.owner,
|
|
84
|
+
repo: context.repo.repo,
|
|
85
|
+
body: `## Preview do Frontend\n🚀 Deploy disponível em: ${process.env.VERCEL_URL}`
|
|
86
|
+
})
|
|
87
|
+
env:
|
|
88
|
+
VERCEL_URL: ${{ steps.deploy.outputs.preview-url }}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Checklist de CI frontend
|
|
92
|
+
|
|
93
|
+
- [ ] Build de produção testado no CI antes do deploy
|
|
94
|
+
- [ ] Variáveis de ambiente de staging separadas das de produção
|
|
95
|
+
- [ ] Preview automático gerado em cada PR
|
|
96
|
+
- [ ] Lint bloqueante — PR não pode ser mergeado com erros de lint
|
|
97
|
+
- [ ] Testes bloqueantes — cobertura mínima configurada
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: clickup
|
|
2
|
+
name: clickup
|
|
3
3
|
description: Organização de projetos e criação de tasks no ClickUp vinculadas ao desenvolvimento. Use quando o desenvolvedor precisar estruturar o backlog, criar tasks para um novo projeto, definir sprints ou entender como nomear branches vinculadas a tasks.
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -14,6 +14,8 @@ Space: [Nome do Projeto]
|
|
|
14
14
|
├── Lista: 👥 [Módulo principal]
|
|
15
15
|
├── Lista: 🎨 Frontend
|
|
16
16
|
├── Lista: 📱 Mobile (se aplicável)
|
|
17
|
+
├── Lista: 🧪 Testes & QA
|
|
18
|
+
├── Lista: 🚀 CI/CD & DevOps
|
|
17
19
|
├── Lista: 📝 Documentação
|
|
18
20
|
└── Lista: 🐛 Bugs
|
|
19
21
|
```
|
|
@@ -22,16 +24,21 @@ Space: [Nome do Projeto]
|
|
|
22
24
|
|
|
23
25
|
```
|
|
24
26
|
🔧 Setup & Infraestrutura
|
|
25
|
-
├── [ ] Inicializar repositório Git
|
|
26
|
-
├── [ ] Configurar banco de dados
|
|
27
|
-
├── [ ] Criar .env.example
|
|
28
|
-
|
|
27
|
+
├── [ ] Inicializar repositório Git → chore/initial-setup
|
|
28
|
+
├── [ ] Configurar banco de dados + Prisma → chore/database-setup
|
|
29
|
+
├── [ ] Criar .env.example → chore/environment-setup
|
|
30
|
+
├── [ ] Configurar GitHub Actions (lint + testes) → ci/setup-actions
|
|
31
|
+
└── [ ] Configurar Husky + Commitlint → chore/git-hooks
|
|
29
32
|
|
|
30
33
|
🔐 Autenticação
|
|
31
|
-
├── [ ] Implementar registro de usuário
|
|
32
|
-
├── [ ] Implementar login com JWT
|
|
33
|
-
├── [ ] Implementar refresh token
|
|
34
|
-
└── [ ] Implementar logout
|
|
34
|
+
├── [ ] Implementar registro de usuário → feature/CK-{id}-user-register
|
|
35
|
+
├── [ ] Implementar login com JWT → feature/CK-{id}-jwt-login
|
|
36
|
+
├── [ ] Implementar refresh token (httpOnly cookie) → feature/CK-{id}-refresh-token
|
|
37
|
+
└── [ ] Implementar logout → feature/CK-{id}-logout
|
|
38
|
+
|
|
39
|
+
🧪 Testes & QA
|
|
40
|
+
├── [ ] Configurar Jest + Supertest (backend) → chore/test-setup-backend
|
|
41
|
+
└── [ ] Configurar Vitest + Testing Library (frontend)→ chore/test-setup-frontend
|
|
35
42
|
```
|
|
36
43
|
|
|
37
44
|
## Padrão de task
|
|
@@ -45,21 +52,37 @@ DESCRIÇÃO:
|
|
|
45
52
|
[Por que essa task existe]
|
|
46
53
|
|
|
47
54
|
## Critérios de Aceitação
|
|
48
|
-
- [ ] [critério verificável]
|
|
49
|
-
- [ ] [critério verificável]
|
|
55
|
+
- [ ] [critério verificável e testável]
|
|
56
|
+
- [ ] [critério verificável e testável]
|
|
57
|
+
- [ ] Testes escritos e passando
|
|
58
|
+
- [ ] PR revisado e aprovado
|
|
50
59
|
|
|
51
60
|
## Branch Git
|
|
52
61
|
feature/CK-{id}-{slug}
|
|
62
|
+
|
|
63
|
+
## Estimativa
|
|
64
|
+
[XS / S / M / L / XL]
|
|
53
65
|
```
|
|
54
66
|
|
|
67
|
+
## Estimativas (T-Shirt sizing)
|
|
68
|
+
|
|
69
|
+
| Tamanho | Horas | Exemplos |
|
|
70
|
+
|---------|-------|---------|
|
|
71
|
+
| XS | < 2h | Fix de bug simples, ajuste de UI |
|
|
72
|
+
| S | 2-4h | CRUD simples, componente básico |
|
|
73
|
+
| M | 4-8h | Feature com lógica de negócio |
|
|
74
|
+
| L | 1-2d | Módulo completo (auth, pagamentos) |
|
|
75
|
+
| XL | > 2d | Arquitetura, migração, refactor grande |
|
|
76
|
+
|
|
55
77
|
## Status do fluxo
|
|
56
78
|
|
|
57
79
|
| Status | Significado |
|
|
58
80
|
|--------|-------------|
|
|
59
81
|
| Backlog | Definida, não iniciada |
|
|
60
|
-
| Em andamento | Branch criada |
|
|
61
|
-
| Em revisão | PR aberto |
|
|
62
|
-
| Bloqueada | Dependência pendente |
|
|
82
|
+
| Em andamento | Branch criada, dev trabalhando |
|
|
83
|
+
| Em revisão | PR aberto, aguardando review |
|
|
84
|
+
| Bloqueada | Dependência pendente — descrever o bloqueio |
|
|
85
|
+
| QA | Em testes/validação |
|
|
63
86
|
| Concluída | PR mergeado em develop |
|
|
64
87
|
|
|
65
88
|
## Vinculação Git ↔ ClickUp
|
|
@@ -73,3 +96,29 @@ git commit -m "feat(auth): implementar JWT login
|
|
|
73
96
|
|
|
74
97
|
Closes CK-42"
|
|
75
98
|
```
|
|
99
|
+
|
|
100
|
+
## Sprint Planning
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Duração: 2 semanas
|
|
104
|
+
Capacidade padrão: 60% do tempo total (40% para bugs/reuniões/imprevistos)
|
|
105
|
+
|
|
106
|
+
Exemplo sprint de 2 semanas (1 dev):
|
|
107
|
+
80h totais × 60% = ~48h disponíveis
|
|
108
|
+
Tasks: 2L + 3M + 4S = 2×12h + 3×6h + 4×3h = 24+18+12 = 54h ≈ ok
|
|
109
|
+
|
|
110
|
+
Daily standup (15min):
|
|
111
|
+
1. O que fiz ontem?
|
|
112
|
+
2. O que farei hoje?
|
|
113
|
+
3. Algum bloqueio?
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Checklist de task bem definida
|
|
117
|
+
|
|
118
|
+
- [ ] Título começa com verbo no infinitivo
|
|
119
|
+
- [ ] Contexto explica o "por quê"
|
|
120
|
+
- [ ] Critérios de aceitação são verificáveis (não subjetivos)
|
|
121
|
+
- [ ] Branch Git definida com ID da task
|
|
122
|
+
- [ ] Estimativa de tamanho preenchida
|
|
123
|
+
- [ ] Dependências mapeadas (se houver)
|
|
124
|
+
- [ ] Inclui critério de teste passando
|