innovationhub-cli 1.1.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -86
- package/index.js +228 -29
- package/package.json +12 -3
- package/templates/nest/.env.example +41 -0
- package/templates/nest/.prettierrc +4 -0
- package/templates/nest/Dockerfile +17 -0
- package/templates/nest/README.md +224 -0
- package/templates/nest/addons/.github/dependabot.yml +11 -0
- package/templates/nest/addons/.github/labeler.yml +34 -0
- package/templates/nest/addons/.github/workflows/check-branch.yml +24 -0
- package/templates/nest/addons/.github/workflows/ci.yml +29 -0
- package/templates/nest/addons/.github/workflows/draft-release.yml +22 -0
- package/templates/nest/addons/.github/workflows/pr-labeler.yml +16 -0
- package/templates/nest/addons/.github/workflows/release.yml +33 -0
- package/templates/nest/addons/.github/workflows/security-audit.yml +17 -0
- package/templates/nest/addons/.github/workflows/semantic-pr.yml +31 -0
- package/templates/nest/addons/.github/workflows/stale.yml +24 -0
- package/templates/nest/addons/.husky/commit-msg +17 -0
- package/templates/nest/addons/.husky/pre-commit +1 -0
- package/templates/nest/addons/addons.json +17 -0
- package/templates/nest/addons/cloudinary/cloudinary.module.ts +11 -0
- package/templates/nest/addons/cloudinary/cloudinary.provider.ts +16 -0
- package/templates/nest/addons/cloudinary/cloudinary.service.ts +54 -0
- package/templates/nest/docker-compose.yml +58 -0
- package/templates/nest/eslint.config.mjs +34 -0
- package/templates/nest/jest.config.js +17 -0
- package/templates/nest/nest-cli.json +12 -0
- package/templates/nest/package.json +99 -0
- package/templates/nest/src/app.controller.ts +7 -0
- package/templates/nest/src/app.module.ts +69 -0
- package/templates/nest/src/app.service.ts +4 -0
- package/templates/nest/src/auth/auth.controller.ts +97 -0
- package/templates/nest/src/auth/auth.module.ts +46 -0
- package/templates/nest/src/auth/auth.service.ts +231 -0
- package/templates/nest/src/auth/decorators/roles.decorator.ts +5 -0
- package/templates/nest/src/auth/dto/change-password.dto.ts +21 -0
- package/templates/nest/src/auth/dto/login-response.dto.ts +25 -0
- package/templates/nest/src/auth/dto/login.dto.ts +15 -0
- package/templates/nest/src/auth/dto/refresh-token.dto.ts +12 -0
- package/templates/nest/src/auth/entities/refresh-token.entity.ts +18 -0
- package/templates/nest/src/auth/enums/role.enum.ts +4 -0
- package/templates/nest/src/auth/guards/jwt-auth.guard.ts +5 -0
- package/templates/nest/src/auth/guards/refresh-token.guard.ts +5 -0
- package/templates/nest/src/auth/guards/roles.guard.ts +23 -0
- package/templates/nest/src/auth/interfaces/jwt-payload.interface.ts +10 -0
- package/templates/nest/src/auth/strategies/jwt.strategy.ts +28 -0
- package/templates/nest/src/auth/strategies/local.strategy.ts +23 -0
- package/templates/nest/src/auth/strategies/refresh-token.strategy.ts +32 -0
- package/templates/nest/src/common/base.entity.ts +19 -0
- package/templates/nest/src/common/base.repository.ts +79 -0
- package/templates/nest/src/common/base.service.ts +28 -0
- package/templates/nest/src/common/constants/errors.constants.ts +33 -0
- package/templates/nest/src/common/decorators/user.decorator.ts +9 -0
- package/templates/nest/src/common/dto/base-query.dto.ts +56 -0
- package/templates/nest/src/common/irepository.ts +18 -0
- package/templates/nest/src/common/utils/duration.utils.ts +33 -0
- package/templates/nest/src/common/utils/pagination.utils.ts +35 -0
- package/templates/nest/src/common/utils/slug.utils.ts +14 -0
- package/templates/nest/src/common/utils/transform.utils.ts +62 -0
- package/templates/nest/src/common/validators/is-date-after.validator.ts +40 -0
- package/templates/nest/src/data-source.ts +23 -0
- package/templates/nest/src/main.ts +44 -0
- package/templates/nest/src/user/dto/create-user.dto.ts +50 -0
- package/templates/nest/src/user/dto/query-users.dto.ts +23 -0
- package/templates/nest/src/user/dto/update-user.dto.ts +15 -0
- package/templates/nest/src/user/entities/user.entity.ts +66 -0
- package/templates/nest/src/user/user.controller.ts +172 -0
- package/templates/nest/src/user/user.module.ts +15 -0
- package/templates/nest/src/user/user.repository.ts +61 -0
- package/templates/nest/src/user/user.service.ts +138 -0
- package/templates/nest/template.json +5 -0
- package/templates/nest/test/jest-e2e.json +12 -0
- package/templates/nest/tsconfig.build.json +4 -0
- package/templates/nest/tsconfig.json +25 -0
- package/templates/python/.env.example +37 -0
- package/templates/python/Dockerfile +18 -0
- package/templates/python/README.md +219 -0
- package/templates/python/addons/.github/dependabot.yml +11 -0
- package/templates/python/addons/.github/labeler.yml +29 -0
- package/templates/python/addons/.github/workflows/check-branch.yml +24 -0
- package/templates/python/addons/.github/workflows/ci.yml +30 -0
- package/templates/python/addons/.github/workflows/draft-release.yml +22 -0
- package/templates/python/addons/.github/workflows/pr-labeler.yml +16 -0
- package/templates/python/addons/.github/workflows/release.yml +30 -0
- package/templates/python/addons/.github/workflows/security-audit.yml +21 -0
- package/templates/python/addons/.github/workflows/semantic-pr.yml +31 -0
- package/templates/python/addons/.github/workflows/stale.yml +24 -0
- package/templates/python/addons/addons.json +17 -0
- package/templates/python/addons/cloudinary/service.py +67 -0
- package/templates/python/addons/pre-commit/.pre-commit-config.yaml +31 -0
- package/templates/python/alembic/env.py +56 -0
- package/templates/python/alembic/script.py.mako +26 -0
- package/templates/python/alembic/versions/.gitkeep +0 -0
- package/templates/python/alembic.ini +39 -0
- package/templates/python/app/__init__.py +0 -0
- package/templates/python/app/auth/__init__.py +5 -0
- package/templates/python/app/auth/dependencies.py +118 -0
- package/templates/python/app/auth/enums.py +6 -0
- package/templates/python/app/auth/models.py +18 -0
- package/templates/python/app/auth/router.py +68 -0
- package/templates/python/app/auth/schemas.py +58 -0
- package/templates/python/app/auth/service.py +180 -0
- package/templates/python/app/common/__init__.py +18 -0
- package/templates/python/app/common/base_model.py +26 -0
- package/templates/python/app/common/base_repository.py +83 -0
- package/templates/python/app/common/errors.py +35 -0
- package/templates/python/app/common/pagination.py +22 -0
- package/templates/python/app/common/schemas.py +20 -0
- package/templates/python/app/common/utils.py +15 -0
- package/templates/python/app/core/__init__.py +4 -0
- package/templates/python/app/core/config.py +55 -0
- package/templates/python/app/core/database.py +20 -0
- package/templates/python/app/main.py +33 -0
- package/templates/python/app/user/__init__.py +4 -0
- package/templates/python/app/user/models.py +26 -0
- package/templates/python/app/user/repository.py +84 -0
- package/templates/python/app/user/router.py +170 -0
- package/templates/python/app/user/schemas.py +60 -0
- package/templates/python/app/user/service.py +114 -0
- package/templates/python/docker-compose.yml +55 -0
- package/templates/python/pyproject.toml +46 -0
- package/templates/python/requirements-dev.txt +7 -0
- package/templates/python/requirements.txt +20 -0
- package/templates/python/template.json +5 -0
- package/utils/template.js +165 -0
- package/utils/git.js +0 -71
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Template NestJS — Innovation Hub
|
|
2
|
+
|
|
3
|
+
Template base para inicialização de projetos backend com **NestJS**. Inclui autenticação completa, gerenciamento de usuários e uma estrutura modular pronta para expandir.
|
|
4
|
+
|
|
5
|
+
## ✨ Funcionalidades Incluídas
|
|
6
|
+
|
|
7
|
+
- **Autenticação e Autorização**: Sistema completo de login com JWT (JSON Web Tokens), refresh tokens rotativos e controle de acesso baseado em papéis (Roles).
|
|
8
|
+
- **Gerenciamento de Usuários**: CRUD de usuários com criptografia de senhas (bcrypt), soft delete, paginação e reset de senha por admin.
|
|
9
|
+
- **Base Genérica Reutilizável**: `BaseEntity`, `BaseRepository`, `BaseService` e `IRepository` para criar novos módulos rapidamente.
|
|
10
|
+
- **Documentação de API**: Geração automática de documentação interativa com **Swagger (OpenAPI)**.
|
|
11
|
+
- **Envio de E-mails**: Serviço de e-mail configurável com templates Handlebars.
|
|
12
|
+
- **Utilitários**: Paginação, geração de slugs, parsing de duração, validadores customizados e constantes de erro centralizadas.
|
|
13
|
+
|
|
14
|
+
## 🚀 Tecnologias Utilizadas
|
|
15
|
+
|
|
16
|
+
- **Framework**: [NestJS](https://nestjs.com/)
|
|
17
|
+
- **Linguagem**: [TypeScript](https://www.typescriptlang.org/)
|
|
18
|
+
- **Banco de Dados**: [PostgreSQL](https://www.postgresql.org/)
|
|
19
|
+
- **ORM**: [TypeORM](https://typeorm.io/)
|
|
20
|
+
- **Containerização**: [Docker](https://www.docker.com/) e Docker Compose
|
|
21
|
+
- **Autenticação**: [Passport.js](http://www.passportjs.org/) (Estratégias `local`, `jwt` e `jwt-refresh`)
|
|
22
|
+
- **Validação de Dados**: `class-validator` e `class-transformer`
|
|
23
|
+
- **Testes**: [Jest](https://jestjs.io/) para testes unitários e E2E.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🏁 Como Começar
|
|
28
|
+
|
|
29
|
+
Siga os passos abaixo para configurar e executar o projeto em seu ambiente local.
|
|
30
|
+
|
|
31
|
+
### Pré-requisitos
|
|
32
|
+
|
|
33
|
+
- [Node.js](https://nodejs.org/en/) (v18 ou superior)
|
|
34
|
+
- [Docker](https://www.docker.com/get-started) e Docker Compose
|
|
35
|
+
- [NPM](https://www.npmjs.com/)
|
|
36
|
+
|
|
37
|
+
### 1. Clone o Repositório
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone <URL_DO_REPOSITORIO>
|
|
41
|
+
cd <NOME_DO_PROJETO>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Configure as Variáveis de Ambiente
|
|
45
|
+
|
|
46
|
+
Copie o arquivo de exemplo `.env.example` para um novo arquivo chamado `.env` e preencha as variáveis.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# No Windows (prompt de comando)
|
|
50
|
+
copy .env.example .env
|
|
51
|
+
|
|
52
|
+
# No Linux ou macOS
|
|
53
|
+
cp .env.example .env
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Abra o arquivo `.env` e preencha todas as variáveis necessárias, como as credenciais do banco de dados e segredos do JWT. Para o ambiente Docker padrão, as credenciais do Postgres já vêm configuradas no `docker-compose.yml`.
|
|
57
|
+
|
|
58
|
+
### 3. Instale as Dependências
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🐳 Executando com Docker (Recomendado)
|
|
67
|
+
|
|
68
|
+
O projeto está configurado para rodar facilmente com Docker, simplificando a configuração do banco de dados e da API.
|
|
69
|
+
|
|
70
|
+
### Subir o Ambiente de Desenvolvimento
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
docker-compose --profile dev up -d --build
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Subir o Ambiente de Produção
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
docker-compose --profile prod up -d --build
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- A API estará disponível em `http://localhost:3000`.
|
|
83
|
+
- O banco de dados PostgreSQL estará acessível na porta `5432`.
|
|
84
|
+
|
|
85
|
+
### Parar o Ambiente
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
docker-compose down
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## ⚙️ Executando Localmente (Sem Docker)
|
|
94
|
+
|
|
95
|
+
### 1. Execute um Banco de Dados PostgreSQL
|
|
96
|
+
|
|
97
|
+
Garanta que você tenha uma instância do PostgreSQL rodando e que as credenciais no seu arquivo `.env` apontem para ela.
|
|
98
|
+
|
|
99
|
+
### 2. Execute as Migrations
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm run migration:run
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 3. Inicie a Aplicação
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Modo de desenvolvimento com hot-reload
|
|
109
|
+
npm run start:dev
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
A aplicação estará disponível em `http://localhost:3000`.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 📄 Documentação e Endpoints
|
|
117
|
+
|
|
118
|
+
### Acessar a Documentação
|
|
119
|
+
|
|
120
|
+
Com a aplicação em execução, acesse a documentação interativa da API gerada pelo Swagger em:
|
|
121
|
+
**[http://localhost:3000/api/docs](http://localhost:3000/api/docs)**
|
|
122
|
+
|
|
123
|
+
### Resumo dos Endpoints Principais
|
|
124
|
+
|
|
125
|
+
- `POST /auth/login`: Autentica um usuário e retorna tokens JWT.
|
|
126
|
+
- `POST /auth/logout`: Faz logout (revoga refresh token).
|
|
127
|
+
- `POST /auth/refresh`: Atualiza os tokens de acesso usando um refresh token.
|
|
128
|
+
- `PATCH /auth/change-password`: Altera a senha do usuário logado.
|
|
129
|
+
- `GET /users/me`: Retorna o perfil do usuário autenticado.
|
|
130
|
+
- `PATCH /users/me`: Atualiza o perfil do usuário autenticado.
|
|
131
|
+
- `GET /users`: Lista todos os usuários (admin).
|
|
132
|
+
- `GET /users/paginated`: Lista usuários com paginação e busca (admin).
|
|
133
|
+
- `GET /users/:id`: Busca um usuário pelo ID (admin).
|
|
134
|
+
- `POST /users`: Cria um novo usuário (admin).
|
|
135
|
+
- `PATCH /users/:id`: Atualiza um usuário pelo ID (admin).
|
|
136
|
+
- `PATCH /users/:id/reset-password`: Reseta a senha de um usuário (admin).
|
|
137
|
+
- `DELETE /users/:id`: Deleta um usuário (admin).
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 📂 Estrutura do Projeto
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
src/
|
|
145
|
+
├── auth/ # Autenticação: estratégias (JWT, local, refresh), guards, decorators, DTOs
|
|
146
|
+
├── common/ # Base genérica (entity, repository, service), utilitários, validadores, DTOs
|
|
147
|
+
├── user/ # Módulo de gerenciamento de usuários (CRUD completo)
|
|
148
|
+
├── app.module.ts # Módulo raiz da aplicação
|
|
149
|
+
├── main.ts # Arquivo de entrada (bootstrap da aplicação)
|
|
150
|
+
└── data-source.ts# Configuração da conexão com o banco de dados para o TypeORM
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 🔌 Addons Disponíveis
|
|
156
|
+
|
|
157
|
+
Na pasta `addons/` do repositório de templates, você encontra módulos opcionais que podem ser adicionados ao projeto:
|
|
158
|
+
|
|
159
|
+
| Addon | Descrição |
|
|
160
|
+
| ------------ | -------------------------------------------------------------------- |
|
|
161
|
+
| `.github` | Workflows de CI/CD, Dependabot, labeler, semantic PR, stale issues |
|
|
162
|
+
| `.husky` | Git hooks para Conventional Commits e lint pré-commit |
|
|
163
|
+
| `cloudinary` | Módulo NestJS para upload, delete e replace de imagens no Cloudinary |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 🔧 Scripts Úteis
|
|
168
|
+
|
|
169
|
+
### Migrations do TypeORM
|
|
170
|
+
|
|
171
|
+
- **Gerar uma nova migration a partir das mudanças nas entidades:**
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm run migration:generate -- -n NomeDaMigration
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
- **Executar migrations pendentes:**
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm run migration:run
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- **Reverter a última migration:**
|
|
184
|
+
```bash
|
|
185
|
+
npm run migration:revert
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Testes
|
|
189
|
+
|
|
190
|
+
- **Executar todos os testes unitários e de integração:**
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npm run test
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
- **Executar testes em modo de observação:**
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npm run test:watch
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- **Verificar a cobertura de testes:**
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
npm run test:cov
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- **Executar testes end-to-end (E2E):**
|
|
209
|
+
```bash
|
|
210
|
+
npm run test:e2e
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Lint e Formatação
|
|
214
|
+
|
|
215
|
+
- **Verificar e corrigir erros de lint com ESLint:**
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
npm run lint
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
- **Formatar o código com Prettier:**
|
|
222
|
+
```bash
|
|
223
|
+
npm run format
|
|
224
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Area Labels
|
|
2
|
+
area/auth:
|
|
3
|
+
- src/auth/**/*
|
|
4
|
+
- src/common/guards/**/*
|
|
5
|
+
- src/common/decorators/**/*
|
|
6
|
+
|
|
7
|
+
area/user:
|
|
8
|
+
- src/user/**/*
|
|
9
|
+
|
|
10
|
+
area/project:
|
|
11
|
+
- src/project/**/*
|
|
12
|
+
|
|
13
|
+
area/news:
|
|
14
|
+
- src/news/**/*
|
|
15
|
+
|
|
16
|
+
area/event:
|
|
17
|
+
- src/event/**/*
|
|
18
|
+
|
|
19
|
+
# Type Labels (Inferred from files)
|
|
20
|
+
documentation:
|
|
21
|
+
- README.md
|
|
22
|
+
- LICENSE
|
|
23
|
+
- '**/*.md'
|
|
24
|
+
|
|
25
|
+
ci:
|
|
26
|
+
- .github/**/*
|
|
27
|
+
|
|
28
|
+
test:
|
|
29
|
+
- test/**/*
|
|
30
|
+
- '**/*.spec.ts'
|
|
31
|
+
|
|
32
|
+
dependencies:
|
|
33
|
+
- package.json
|
|
34
|
+
- package-lock.json
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Check Branch Up-to-Date
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ main, develop, master, dev ]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
check-up-to-date:
|
|
9
|
+
name: Check if branch is up-to-date
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- name: Checkout code
|
|
13
|
+
uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
|
|
17
|
+
- name: Check if branch is up-to-date
|
|
18
|
+
run: |
|
|
19
|
+
git fetch origin ${{ github.base_ref }}
|
|
20
|
+
git fetch origin ${{ github.head_ref }}
|
|
21
|
+
if ! git merge-base --is-ancestor origin/${{ github.base_ref }} origin/${{ github.head_ref }}; then
|
|
22
|
+
echo "::error::Branch is behind ${{ github.base_ref }}. Please merge/rebase before continuing."
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [ main, develop, master, dev ]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [ main, develop, master, dev ]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-and-test:
|
|
10
|
+
name: Build and Test
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
node-version: [24.x]
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout code
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: ${{ matrix.node-version }}
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: npm install
|
|
25
|
+
- name: Lint
|
|
26
|
+
run: npm run lint
|
|
27
|
+
|
|
28
|
+
- name: Build
|
|
29
|
+
run: npm run build
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Release Drafter
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
types: [opened, reopened, synchronize]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
update_release_draft:
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
pull-requests: write
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: release-drafter/release-drafter@v6
|
|
21
|
+
env:
|
|
22
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: "Pull Request Labeler"
|
|
2
|
+
on:
|
|
3
|
+
pull_request_target:
|
|
4
|
+
types: [opened, synchronize, reopened]
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
triage:
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pull-requests: write
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/labeler@v5
|
|
14
|
+
with:
|
|
15
|
+
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
16
|
+
sync-labels: true
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
name: Create Release
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout code
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Setup Node.js
|
|
19
|
+
uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: '20.x'
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: npm install
|
|
25
|
+
|
|
26
|
+
- name: Build
|
|
27
|
+
run: npm run build
|
|
28
|
+
|
|
29
|
+
- name: Create Release
|
|
30
|
+
uses: softprops/action-gh-release@v1
|
|
31
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
32
|
+
with:
|
|
33
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: Security Audit
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, develop, master, dev ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main, develop, master, dev ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
audit:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- name: Install dependencies
|
|
15
|
+
run: npm install
|
|
16
|
+
- name: Audit components
|
|
17
|
+
run: npm audit --audit-level=critical
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Semantic PR
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types:
|
|
6
|
+
- opened
|
|
7
|
+
- edited
|
|
8
|
+
- synchronize
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
main:
|
|
12
|
+
name: Validate PR title
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: amannn/action-semantic-pull-request@v5
|
|
16
|
+
env:
|
|
17
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
18
|
+
with:
|
|
19
|
+
types: |
|
|
20
|
+
feat
|
|
21
|
+
fix
|
|
22
|
+
docs
|
|
23
|
+
style
|
|
24
|
+
refactor
|
|
25
|
+
perf
|
|
26
|
+
test
|
|
27
|
+
build
|
|
28
|
+
ci
|
|
29
|
+
chore
|
|
30
|
+
revert
|
|
31
|
+
requireScope: false
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: "Stale"
|
|
2
|
+
on:
|
|
3
|
+
schedule:
|
|
4
|
+
- cron: "30 1 */4 * *"
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
stale:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions:
|
|
10
|
+
issues: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/stale@v9
|
|
14
|
+
with:
|
|
15
|
+
stale-issue-message: "Esta issue está inativa há 60 dias. Marque como 'fresco' ou comente para reativar."
|
|
16
|
+
stale-pr-message: "Este PR está inativo há 60 dias. Marque como 'fresco' ou comente para reativar."
|
|
17
|
+
close-issue-message: "Esta issue foi fechada por inatividade."
|
|
18
|
+
close-pr-message: "Este PR foi fechado por inatividade."
|
|
19
|
+
days-before-issue-stale: 60
|
|
20
|
+
days-before-pr-stale: 60
|
|
21
|
+
days-before-issue-close: 7
|
|
22
|
+
days-before-pr-close: 7
|
|
23
|
+
exempt-issue-labels: "security,bug,enhancement,pinned,long-term"
|
|
24
|
+
exempt-pr-labels: "security,bug,enhancement,pinned,long-term"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# Regex for Conventional Commits
|
|
4
|
+
pattern="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?: .+$"
|
|
5
|
+
|
|
6
|
+
while read -r line; do
|
|
7
|
+
if ! echo "$line" | grep -qE "$pattern"; then
|
|
8
|
+
echo "❌ Invalid commit message format."
|
|
9
|
+
echo "Please use the Conventional Commits pattern:"
|
|
10
|
+
echo " <type>(<scope>): <subject>"
|
|
11
|
+
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
|
|
12
|
+
echo "Example: feat(auth): add google login"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
# Only check the first line (subject)
|
|
16
|
+
break
|
|
17
|
+
done < "$1"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npm run lint
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "cloudinary",
|
|
4
|
+
"label": "Cloudinary (Upload de Imagens)",
|
|
5
|
+
"dest": "src/cloudinary"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"name": ".github",
|
|
9
|
+
"label": "GitHub Actions (CI/CD)",
|
|
10
|
+
"dest": ".github"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": ".husky",
|
|
14
|
+
"label": "Husky (Lint & Commits)",
|
|
15
|
+
"dest": ".husky"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { ConfigModule } from '@nestjs/config';
|
|
3
|
+
import { CloudinaryProvider } from './cloudinary.provider';
|
|
4
|
+
import { CloudinaryService } from './cloudinary.service';
|
|
5
|
+
|
|
6
|
+
@Module({
|
|
7
|
+
imports: [ConfigModule],
|
|
8
|
+
providers: [CloudinaryProvider, CloudinaryService],
|
|
9
|
+
exports: [CloudinaryService],
|
|
10
|
+
})
|
|
11
|
+
export class CloudinaryModule {}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { v2 as cloudinary } from 'cloudinary';
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
|
|
4
|
+
export const CloudinaryProvider = {
|
|
5
|
+
provide: 'CLOUDINARY',
|
|
6
|
+
useFactory: (configService: ConfigService) => {
|
|
7
|
+
cloudinary.config({
|
|
8
|
+
cloud_name: configService.get<string>('CLOUDINARY_CLOUD_NAME'),
|
|
9
|
+
api_key: configService.get<string>('CLOUDINARY_API_KEY'),
|
|
10
|
+
api_secret: configService.get<string>('CLOUDINARY_API_SECRET'),
|
|
11
|
+
secure: true,
|
|
12
|
+
});
|
|
13
|
+
return cloudinary;
|
|
14
|
+
},
|
|
15
|
+
inject: [ConfigService],
|
|
16
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Injectable, Inject, BadRequestException } from '@nestjs/common';
|
|
2
|
+
import { UploadApiResponse, v2 as cloudinaryType } from 'cloudinary';
|
|
3
|
+
import { ERRORS } from '../common/constants/errors.constants';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class CloudinaryService {
|
|
7
|
+
constructor(
|
|
8
|
+
@Inject('CLOUDINARY') private cloudinaryInstance: typeof cloudinaryType,
|
|
9
|
+
) {}
|
|
10
|
+
|
|
11
|
+
async uploadImage(
|
|
12
|
+
file: Express.Multer.File,
|
|
13
|
+
folder: string,
|
|
14
|
+
): Promise<UploadApiResponse> {
|
|
15
|
+
if (!file || !file.buffer) {
|
|
16
|
+
throw new BadRequestException(ERRORS.IMAGE.REQUIRED);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const fileBase64 = file.buffer.toString('base64');
|
|
20
|
+
const dataUri = `data:${file.mimetype};base64,${fileBase64}`;
|
|
21
|
+
|
|
22
|
+
return this.cloudinaryInstance.uploader.upload(dataUri, {
|
|
23
|
+
folder: folder,
|
|
24
|
+
resource_type: 'image',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async deleteImage(publicId: string): Promise<{ result: string }> {
|
|
29
|
+
return this.cloudinaryInstance.uploader.destroy(publicId) as Promise<{
|
|
30
|
+
result: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async replaceImage(
|
|
35
|
+
file: Express.Multer.File,
|
|
36
|
+
folder: string,
|
|
37
|
+
oldPublicId?: string,
|
|
38
|
+
): Promise<UploadApiResponse> {
|
|
39
|
+
if (!file) {
|
|
40
|
+
throw new BadRequestException(ERRORS.IMAGE.REQUIRED);
|
|
41
|
+
}
|
|
42
|
+
if (oldPublicId) {
|
|
43
|
+
await this.deleteImage(oldPublicId);
|
|
44
|
+
}
|
|
45
|
+
return this.uploadImage(file, folder);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async deleteImages(publicIds: string[]): Promise<Record<string, unknown>> {
|
|
49
|
+
if (!publicIds.length) return {};
|
|
50
|
+
return this.cloudinaryInstance.api.delete_resources(publicIds) as Promise<
|
|
51
|
+
Record<string, unknown>
|
|
52
|
+
>;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
version: "3.9"
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
api-prod:
|
|
5
|
+
container_name: api_prod
|
|
6
|
+
build:
|
|
7
|
+
context: .
|
|
8
|
+
dockerfile: Dockerfile
|
|
9
|
+
target: production
|
|
10
|
+
command: npm run start:prod
|
|
11
|
+
ports:
|
|
12
|
+
- "3000:3000"
|
|
13
|
+
env_file:
|
|
14
|
+
- .env
|
|
15
|
+
depends_on:
|
|
16
|
+
postgres:
|
|
17
|
+
condition: service_healthy
|
|
18
|
+
restart: unless-stopped
|
|
19
|
+
profiles: ["prod"]
|
|
20
|
+
|
|
21
|
+
api-dev:
|
|
22
|
+
container_name: api_dev
|
|
23
|
+
build:
|
|
24
|
+
context: .
|
|
25
|
+
dockerfile: Dockerfile
|
|
26
|
+
target: development
|
|
27
|
+
command: npm run start:dev
|
|
28
|
+
ports:
|
|
29
|
+
- "3000:3000"
|
|
30
|
+
env_file:
|
|
31
|
+
- .env
|
|
32
|
+
depends_on:
|
|
33
|
+
postgres:
|
|
34
|
+
condition: service_healthy
|
|
35
|
+
volumes:
|
|
36
|
+
- .:/usr/src/app
|
|
37
|
+
- /usr/src/app/node_modules
|
|
38
|
+
restart: unless-stopped
|
|
39
|
+
profiles: ["dev"]
|
|
40
|
+
|
|
41
|
+
postgres:
|
|
42
|
+
image: postgres:15
|
|
43
|
+
container_name: postgres
|
|
44
|
+
restart: unless-stopped
|
|
45
|
+
healthcheck:
|
|
46
|
+
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
|
47
|
+
interval: 10s
|
|
48
|
+
timeout: 5s
|
|
49
|
+
retries: 5
|
|
50
|
+
env_file:
|
|
51
|
+
- .env
|
|
52
|
+
ports:
|
|
53
|
+
- "5432:5432"
|
|
54
|
+
volumes:
|
|
55
|
+
- db_data:/var/lib/postgresql/data
|
|
56
|
+
|
|
57
|
+
volumes:
|
|
58
|
+
db_data:
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import eslint from '@eslint/js';
|
|
3
|
+
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
4
|
+
import globals from 'globals';
|
|
5
|
+
import tseslint from 'typescript-eslint';
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{
|
|
9
|
+
ignores: ['eslint.config.mjs'],
|
|
10
|
+
},
|
|
11
|
+
eslint.configs.recommended,
|
|
12
|
+
...tseslint.configs.recommendedTypeChecked,
|
|
13
|
+
eslintPluginPrettierRecommended,
|
|
14
|
+
{
|
|
15
|
+
languageOptions: {
|
|
16
|
+
globals: {
|
|
17
|
+
...globals.node,
|
|
18
|
+
...globals.jest,
|
|
19
|
+
},
|
|
20
|
+
sourceType: 'commonjs',
|
|
21
|
+
parserOptions: {
|
|
22
|
+
projectService: true,
|
|
23
|
+
tsconfigRootDir: import.meta.dirname,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
rules: {
|
|
29
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
30
|
+
'@typescript-eslint/no-floating-promises': 'warn',
|
|
31
|
+
'@typescript-eslint/no-unsafe-argument': 'warn'
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
);
|