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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -86
  3. package/index.js +228 -29
  4. package/package.json +12 -3
  5. package/templates/nest/.env.example +41 -0
  6. package/templates/nest/.prettierrc +4 -0
  7. package/templates/nest/Dockerfile +17 -0
  8. package/templates/nest/README.md +224 -0
  9. package/templates/nest/addons/.github/dependabot.yml +11 -0
  10. package/templates/nest/addons/.github/labeler.yml +34 -0
  11. package/templates/nest/addons/.github/workflows/check-branch.yml +24 -0
  12. package/templates/nest/addons/.github/workflows/ci.yml +29 -0
  13. package/templates/nest/addons/.github/workflows/draft-release.yml +22 -0
  14. package/templates/nest/addons/.github/workflows/pr-labeler.yml +16 -0
  15. package/templates/nest/addons/.github/workflows/release.yml +33 -0
  16. package/templates/nest/addons/.github/workflows/security-audit.yml +17 -0
  17. package/templates/nest/addons/.github/workflows/semantic-pr.yml +31 -0
  18. package/templates/nest/addons/.github/workflows/stale.yml +24 -0
  19. package/templates/nest/addons/.husky/commit-msg +17 -0
  20. package/templates/nest/addons/.husky/pre-commit +1 -0
  21. package/templates/nest/addons/addons.json +17 -0
  22. package/templates/nest/addons/cloudinary/cloudinary.module.ts +11 -0
  23. package/templates/nest/addons/cloudinary/cloudinary.provider.ts +16 -0
  24. package/templates/nest/addons/cloudinary/cloudinary.service.ts +54 -0
  25. package/templates/nest/docker-compose.yml +58 -0
  26. package/templates/nest/eslint.config.mjs +34 -0
  27. package/templates/nest/jest.config.js +17 -0
  28. package/templates/nest/nest-cli.json +12 -0
  29. package/templates/nest/package.json +99 -0
  30. package/templates/nest/src/app.controller.ts +7 -0
  31. package/templates/nest/src/app.module.ts +69 -0
  32. package/templates/nest/src/app.service.ts +4 -0
  33. package/templates/nest/src/auth/auth.controller.ts +97 -0
  34. package/templates/nest/src/auth/auth.module.ts +46 -0
  35. package/templates/nest/src/auth/auth.service.ts +231 -0
  36. package/templates/nest/src/auth/decorators/roles.decorator.ts +5 -0
  37. package/templates/nest/src/auth/dto/change-password.dto.ts +21 -0
  38. package/templates/nest/src/auth/dto/login-response.dto.ts +25 -0
  39. package/templates/nest/src/auth/dto/login.dto.ts +15 -0
  40. package/templates/nest/src/auth/dto/refresh-token.dto.ts +12 -0
  41. package/templates/nest/src/auth/entities/refresh-token.entity.ts +18 -0
  42. package/templates/nest/src/auth/enums/role.enum.ts +4 -0
  43. package/templates/nest/src/auth/guards/jwt-auth.guard.ts +5 -0
  44. package/templates/nest/src/auth/guards/refresh-token.guard.ts +5 -0
  45. package/templates/nest/src/auth/guards/roles.guard.ts +23 -0
  46. package/templates/nest/src/auth/interfaces/jwt-payload.interface.ts +10 -0
  47. package/templates/nest/src/auth/strategies/jwt.strategy.ts +28 -0
  48. package/templates/nest/src/auth/strategies/local.strategy.ts +23 -0
  49. package/templates/nest/src/auth/strategies/refresh-token.strategy.ts +32 -0
  50. package/templates/nest/src/common/base.entity.ts +19 -0
  51. package/templates/nest/src/common/base.repository.ts +79 -0
  52. package/templates/nest/src/common/base.service.ts +28 -0
  53. package/templates/nest/src/common/constants/errors.constants.ts +33 -0
  54. package/templates/nest/src/common/decorators/user.decorator.ts +9 -0
  55. package/templates/nest/src/common/dto/base-query.dto.ts +56 -0
  56. package/templates/nest/src/common/irepository.ts +18 -0
  57. package/templates/nest/src/common/utils/duration.utils.ts +33 -0
  58. package/templates/nest/src/common/utils/pagination.utils.ts +35 -0
  59. package/templates/nest/src/common/utils/slug.utils.ts +14 -0
  60. package/templates/nest/src/common/utils/transform.utils.ts +62 -0
  61. package/templates/nest/src/common/validators/is-date-after.validator.ts +40 -0
  62. package/templates/nest/src/data-source.ts +23 -0
  63. package/templates/nest/src/main.ts +44 -0
  64. package/templates/nest/src/user/dto/create-user.dto.ts +50 -0
  65. package/templates/nest/src/user/dto/query-users.dto.ts +23 -0
  66. package/templates/nest/src/user/dto/update-user.dto.ts +15 -0
  67. package/templates/nest/src/user/entities/user.entity.ts +66 -0
  68. package/templates/nest/src/user/user.controller.ts +172 -0
  69. package/templates/nest/src/user/user.module.ts +15 -0
  70. package/templates/nest/src/user/user.repository.ts +61 -0
  71. package/templates/nest/src/user/user.service.ts +138 -0
  72. package/templates/nest/template.json +5 -0
  73. package/templates/nest/test/jest-e2e.json +12 -0
  74. package/templates/nest/tsconfig.build.json +4 -0
  75. package/templates/nest/tsconfig.json +25 -0
  76. package/templates/python/.env.example +37 -0
  77. package/templates/python/Dockerfile +18 -0
  78. package/templates/python/README.md +219 -0
  79. package/templates/python/addons/.github/dependabot.yml +11 -0
  80. package/templates/python/addons/.github/labeler.yml +29 -0
  81. package/templates/python/addons/.github/workflows/check-branch.yml +24 -0
  82. package/templates/python/addons/.github/workflows/ci.yml +30 -0
  83. package/templates/python/addons/.github/workflows/draft-release.yml +22 -0
  84. package/templates/python/addons/.github/workflows/pr-labeler.yml +16 -0
  85. package/templates/python/addons/.github/workflows/release.yml +30 -0
  86. package/templates/python/addons/.github/workflows/security-audit.yml +21 -0
  87. package/templates/python/addons/.github/workflows/semantic-pr.yml +31 -0
  88. package/templates/python/addons/.github/workflows/stale.yml +24 -0
  89. package/templates/python/addons/addons.json +17 -0
  90. package/templates/python/addons/cloudinary/service.py +67 -0
  91. package/templates/python/addons/pre-commit/.pre-commit-config.yaml +31 -0
  92. package/templates/python/alembic/env.py +56 -0
  93. package/templates/python/alembic/script.py.mako +26 -0
  94. package/templates/python/alembic/versions/.gitkeep +0 -0
  95. package/templates/python/alembic.ini +39 -0
  96. package/templates/python/app/__init__.py +0 -0
  97. package/templates/python/app/auth/__init__.py +5 -0
  98. package/templates/python/app/auth/dependencies.py +118 -0
  99. package/templates/python/app/auth/enums.py +6 -0
  100. package/templates/python/app/auth/models.py +18 -0
  101. package/templates/python/app/auth/router.py +68 -0
  102. package/templates/python/app/auth/schemas.py +58 -0
  103. package/templates/python/app/auth/service.py +180 -0
  104. package/templates/python/app/common/__init__.py +18 -0
  105. package/templates/python/app/common/base_model.py +26 -0
  106. package/templates/python/app/common/base_repository.py +83 -0
  107. package/templates/python/app/common/errors.py +35 -0
  108. package/templates/python/app/common/pagination.py +22 -0
  109. package/templates/python/app/common/schemas.py +20 -0
  110. package/templates/python/app/common/utils.py +15 -0
  111. package/templates/python/app/core/__init__.py +4 -0
  112. package/templates/python/app/core/config.py +55 -0
  113. package/templates/python/app/core/database.py +20 -0
  114. package/templates/python/app/main.py +33 -0
  115. package/templates/python/app/user/__init__.py +4 -0
  116. package/templates/python/app/user/models.py +26 -0
  117. package/templates/python/app/user/repository.py +84 -0
  118. package/templates/python/app/user/router.py +170 -0
  119. package/templates/python/app/user/schemas.py +60 -0
  120. package/templates/python/app/user/service.py +114 -0
  121. package/templates/python/docker-compose.yml +55 -0
  122. package/templates/python/pyproject.toml +46 -0
  123. package/templates/python/requirements-dev.txt +7 -0
  124. package/templates/python/requirements.txt +20 -0
  125. package/templates/python/template.json +5 -0
  126. package/utils/template.js +165 -0
  127. package/utils/git.js +0 -71
@@ -0,0 +1,219 @@
1
+ # Template FastAPI — Innovation Hub
2
+
3
+ Template base para inicialização de projetos backend com **FastAPI**. 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**: `BaseModel`, `BaseRepository` com generics Python para criar novos módulos rapidamente.
10
+ - **Documentação de API**: Geração automática de documentação interativa com **Swagger (OpenAPI)** — nativa do FastAPI.
11
+ - **Utilitários**: Paginação, geração de slugs, constantes de erro centralizadas e query params base.
12
+
13
+ ## 🚀 Tecnologias Utilizadas
14
+
15
+ - **Framework**: [FastAPI](https://fastapi.tiangolo.com/)
16
+ - **Linguagem**: [Python](https://www.python.org/) (3.11+)
17
+ - **Banco de Dados**: [PostgreSQL](https://www.postgresql.org/)
18
+ - **ORM**: [SQLAlchemy 2.0](https://www.sqlalchemy.org/) (async)
19
+ - **Migrations**: [Alembic](https://alembic.sqlalchemy.org/)
20
+ - **Containerização**: [Docker](https://www.docker.com/) e Docker Compose
21
+ - **Autenticação**: [python-jose](https://python-jose.readthedocs.io/) (JWT) + [passlib](https://passlib.readthedocs.io/) (bcrypt)
22
+ - **Validação de Dados**: [Pydantic v2](https://docs.pydantic.dev/)
23
+ - **Configuração**: [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)
24
+ - **Testes**: [pytest](https://pytest.org/) + [httpx](https://www.python-httpx.org/)
25
+ - **Lint/Formatação**: [ruff](https://docs.astral.sh/ruff/)
26
+
27
+ ---
28
+
29
+ ## 🏁 Como Começar
30
+
31
+ ### Pré-requisitos
32
+
33
+ - [Python](https://www.python.org/) (3.11 ou superior)
34
+ - [Docker](https://www.docker.com/get-started) e Docker Compose
35
+
36
+ ### 1. Clone o Repositório
37
+
38
+ ```bash
39
+ git clone <URL_DO_REPOSITORIO>
40
+ cd <NOME_DO_PROJETO>
41
+ ```
42
+
43
+ ### 2. Configure as Variáveis de Ambiente
44
+
45
+ ```bash
46
+ # No Windows
47
+ copy .env.example .env
48
+
49
+ # No Linux ou macOS
50
+ cp .env.example .env
51
+ ```
52
+
53
+ Preencha as variáveis no arquivo `.env`. As credenciais padrão do Postgres já funcionam com o Docker Compose.
54
+
55
+ ### 3. Instale as Dependências
56
+
57
+ ```bash
58
+ # Crie um ambiente virtual
59
+ python -m venv .venv
60
+
61
+ # Ative o ambiente virtual
62
+ # Windows:
63
+ .venv\Scripts\activate
64
+ # Linux/macOS:
65
+ source .venv/bin/activate
66
+
67
+ # Instale o projeto
68
+ pip install -e ".[dev]"
69
+ ```
70
+
71
+ ---
72
+
73
+ ## 🐳 Executando com Docker (Recomendado)
74
+
75
+ ### Subir o Ambiente de Desenvolvimento
76
+
77
+ ```bash
78
+ docker-compose --profile dev up -d --build
79
+ ```
80
+
81
+ ### Subir o Ambiente de Produção
82
+
83
+ ```bash
84
+ docker-compose --profile prod up -d --build
85
+ ```
86
+
87
+ - A API estará disponível em `http://localhost:3000`.
88
+ - O banco de dados PostgreSQL estará acessível na porta `5432`.
89
+
90
+ ### Parar o Ambiente
91
+
92
+ ```bash
93
+ docker-compose down
94
+ ```
95
+
96
+ ---
97
+
98
+ ## ⚙️ Executando Localmente (Sem Docker)
99
+
100
+ ### 1. Execute um Banco de Dados PostgreSQL
101
+
102
+ Garanta que uma instância do PostgreSQL esteja rodando e que as credenciais no `.env` estejam corretas.
103
+
104
+ ### 2. Execute as Migrations
105
+
106
+ ```bash
107
+ alembic upgrade head
108
+ ```
109
+
110
+ ### 3. Inicie a Aplicação
111
+
112
+ ```bash
113
+ uvicorn app.main:app --reload --port 3000
114
+ ```
115
+
116
+ A aplicação estará disponível em `http://localhost:3000`.
117
+
118
+ ---
119
+
120
+ ## 📄 Documentação e Endpoints
121
+
122
+ ### Acessar a Documentação
123
+
124
+ Com a aplicação em execução:
125
+
126
+ - **Swagger UI**: [http://localhost:3000/api/docs](http://localhost:3000/api/docs)
127
+ - **ReDoc**: [http://localhost:3000/api/redoc](http://localhost:3000/api/redoc)
128
+
129
+ ### Resumo dos Endpoints Principais
130
+
131
+ - `POST /auth/login`: Autentica um usuário e retorna tokens JWT.
132
+ - `POST /auth/logout`: Faz logout (revoga refresh token).
133
+ - `POST /auth/refresh`: Atualiza os tokens de acesso usando um refresh token.
134
+ - `PATCH /auth/change-password`: Altera a senha do usuário logado.
135
+ - `GET /users/me`: Retorna o perfil do usuário autenticado.
136
+ - `PATCH /users/me`: Atualiza o perfil do usuário autenticado.
137
+ - `GET /users/`: Lista todos os usuários (admin).
138
+ - `GET /users/paginated`: Lista usuários com paginação e busca (admin).
139
+ - `GET /users/{user_id}`: Busca um usuário pelo ID (admin).
140
+ - `POST /users/`: Cria um novo usuário (admin).
141
+ - `PATCH /users/{user_id}`: Atualiza um usuário pelo ID (admin).
142
+ - `PATCH /users/{user_id}/reset-password`: Reseta a senha de um usuário (admin).
143
+ - `DELETE /users/{user_id}`: Deleta um usuário (admin).
144
+
145
+ ---
146
+
147
+ ## 📂 Estrutura do Projeto
148
+
149
+ ```
150
+ app/
151
+ ├── auth/ # Autenticação: JWT, dependencies, schemas, service, router
152
+ ├── common/ # Base genérica (model, repository), utilitários, paginação, schemas
153
+ ├── core/ # Configuração (settings) e banco de dados (SQLAlchemy async)
154
+ ├── user/ # Módulo de gerenciamento de usuários (CRUD completo)
155
+ └── main.py # Ponto de entrada da aplicação (FastAPI bootstrap)
156
+
157
+ alembic/
158
+ ├── env.py # Configuração do Alembic
159
+ ├── script.py.mako # Template de migration
160
+ └── versions/ # Arquivos de migration gerados
161
+ ```
162
+
163
+ ---
164
+
165
+ ## 🔌 Addons Disponíveis
166
+
167
+ Na pasta `addons/` do repositório de templates, você encontra módulos opcionais:
168
+
169
+ | Addon | Descrição |
170
+ | ------------ | --------------------------------------------------------------------- |
171
+ | `.github` | Workflows de CI/CD, Dependabot, labeler, semantic PR, stale issues |
172
+ | `pre-commit` | `.pre-commit-config.yaml` para Conventional Commits e lint pré-commit |
173
+ | `cloudinary` | Módulo Python para upload, delete e replace de imagens no Cloudinary |
174
+
175
+ ---
176
+
177
+ ## 🔧 Scripts Úteis
178
+
179
+ ### Migrations com Alembic
180
+
181
+ ```bash
182
+ # Gerar uma nova migration
183
+ alembic revision --autogenerate -m "descricao da migration"
184
+
185
+ # Executar migrations pendentes
186
+ alembic upgrade head
187
+
188
+ # Reverter a última migration
189
+ alembic downgrade -1
190
+
191
+ # Ver status das migrations
192
+ alembic current
193
+ ```
194
+
195
+ ### Testes
196
+
197
+ ```bash
198
+ # Executar todos os testes
199
+ pytest
200
+
201
+ # Executar com cobertura
202
+ pytest --cov=app
203
+
204
+ # Executar em modo verboso
205
+ pytest -v
206
+ ```
207
+
208
+ ### Lint e Formatação
209
+
210
+ ```bash
211
+ # Verificar erros com ruff
212
+ ruff check .
213
+
214
+ # Corrigir automaticamente
215
+ ruff check --fix .
216
+
217
+ # Formatar código
218
+ ruff format .
219
+ ```
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ groups:
8
+ dependencies:
9
+ patterns:
10
+ - "*"
11
+ open-pull-requests-limit: 10
@@ -0,0 +1,29 @@
1
+ # Area Labels
2
+ area/auth:
3
+ - app/auth/**/*
4
+
5
+ area/user:
6
+ - app/user/**/*
7
+
8
+ area/common:
9
+ - app/common/**/*
10
+
11
+ area/core:
12
+ - app/core/**/*
13
+
14
+ # Type Labels (Inferred from files)
15
+ documentation:
16
+ - README.md
17
+ - LICENSE
18
+ - "**/*.md"
19
+
20
+ ci:
21
+ - .github/**/*
22
+
23
+ test:
24
+ - tests/**/*
25
+ - "**/*test*.py"
26
+
27
+ dependencies:
28
+ - pyproject.toml
29
+ - requirements*.txt
@@ -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,30 @@
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
+ python-version: ["3.11"]
16
+ steps:
17
+ - name: Checkout code
18
+ uses: actions/checkout@v4
19
+ - name: Setup Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ - name: Install dependencies
24
+ run: pip install -e ".[dev]"
25
+ - name: Lint
26
+ run: ruff check .
27
+ - name: Format check
28
+ run: ruff format --check .
29
+ - name: Test
30
+ run: pytest
@@ -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,30 @@
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 Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.11"
22
+
23
+ - name: Install dependencies
24
+ run: pip install -e .
25
+
26
+ - name: Create Release
27
+ uses: softprops/action-gh-release@v1
28
+ if: startsWith(github.ref, 'refs/tags/')
29
+ with:
30
+ generate_release_notes: true
@@ -0,0 +1,21 @@
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: Setup Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.11"
18
+ - name: Install dependencies
19
+ run: pip install -e . pip-audit
20
+ - name: Audit dependencies
21
+ run: pip-audit
@@ -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
+ [
2
+ {
3
+ "name": "cloudinary",
4
+ "label": "Cloudinary (Upload de Imagens)",
5
+ "dest": "app/cloudinary"
6
+ },
7
+ {
8
+ "name": ".github",
9
+ "label": "GitHub Actions (CI/CD)",
10
+ "dest": ".github"
11
+ },
12
+ {
13
+ "name": "pre-commit",
14
+ "label": "Pre-commit (Lint & Formatação)",
15
+ "dest": "."
16
+ }
17
+ ]
@@ -0,0 +1,67 @@
1
+ """
2
+ Addon: Cloudinary — Serviço de upload de imagens.
3
+
4
+ Para usar, adicione 'cloudinary' ao pyproject.toml:
5
+ dependencies = [..., "cloudinary>=1.36.0"]
6
+
7
+ E copie este arquivo para app/cloudinary/service.py
8
+ """
9
+
10
+ import cloudinary
11
+ import cloudinary.uploader
12
+ from fastapi import HTTPException, UploadFile, status
13
+
14
+ from app.common.errors import ERRORS
15
+ from app.core.config import settings
16
+
17
+
18
+ def configure_cloudinary() -> None:
19
+ """Configura o Cloudinary. Chame no startup da aplicação."""
20
+ cloudinary.config(
21
+ cloud_name=settings.CLOUDINARY_CLOUD_NAME,
22
+ api_key=settings.CLOUDINARY_API_KEY,
23
+ api_secret=settings.CLOUDINARY_API_SECRET,
24
+ secure=True,
25
+ )
26
+
27
+
28
+ async def upload_image(file: UploadFile, folder: str) -> dict:
29
+ """Faz upload de uma imagem para o Cloudinary."""
30
+ if not file:
31
+ raise HTTPException(
32
+ status_code=status.HTTP_400_BAD_REQUEST,
33
+ detail=ERRORS["IMAGE"]["REQUIRED"],
34
+ )
35
+
36
+ contents = await file.read()
37
+ import base64
38
+
39
+ file_base64 = base64.b64encode(contents).decode("utf-8")
40
+ data_uri = f"data:{file.content_type};base64,{file_base64}"
41
+
42
+ result = cloudinary.uploader.upload(data_uri, folder=folder, resource_type="image")
43
+ return result
44
+
45
+
46
+ async def delete_image(public_id: str) -> dict:
47
+ """Deleta uma imagem do Cloudinary pelo public_id."""
48
+ return cloudinary.uploader.destroy(public_id)
49
+
50
+
51
+ async def replace_image(file: UploadFile, folder: str, old_public_id: str | None = None) -> dict:
52
+ """Substitui uma imagem: deleta a antiga (se existir) e faz upload da nova."""
53
+ if not file:
54
+ raise HTTPException(
55
+ status_code=status.HTTP_400_BAD_REQUEST,
56
+ detail=ERRORS["IMAGE"]["REQUIRED"],
57
+ )
58
+ if old_public_id:
59
+ await delete_image(old_public_id)
60
+ return await upload_image(file, folder)
61
+
62
+
63
+ async def delete_images(public_ids: list[str]) -> dict:
64
+ """Deleta múltiplas imagens do Cloudinary."""
65
+ if not public_ids:
66
+ return {}
67
+ return cloudinary.api.delete_resources(public_ids)
@@ -0,0 +1,31 @@
1
+ # Addon: pre-commit
2
+ # Equivalente ao .husky do NestJS para projetos Python.
3
+ # Para instalar: pip install pre-commit && pre-commit install
4
+
5
+ repos:
6
+ # Ruff: linter e formatter
7
+ - repo: https://github.com/astral-sh/ruff-pre-commit
8
+ rev: v0.9.0
9
+ hooks:
10
+ - id: ruff
11
+ args: [--fix]
12
+ - id: ruff-format
13
+
14
+ # Conventional Commits
15
+ - repo: https://github.com/compilerla/conventional-pre-commit
16
+ rev: v4.0.0
17
+ hooks:
18
+ - id: conventional-pre-commit
19
+ stages: [commit-msg]
20
+ args:
21
+ - feat
22
+ - fix
23
+ - docs
24
+ - style
25
+ - refactor
26
+ - perf
27
+ - test
28
+ - build
29
+ - ci
30
+ - chore
31
+ - revert
@@ -0,0 +1,56 @@
1
+ from logging.config import fileConfig
2
+
3
+ from sqlalchemy import engine_from_config, pool
4
+
5
+ from alembic import context
6
+ from app.auth.models import RefreshToken # noqa: F401
7
+ from app.common.base_model import Base
8
+ from app.core.config import settings
9
+
10
+ # Importar todos os models para que o Alembic os detecte
11
+ from app.user.models import User # noqa: F401
12
+
13
+ config = context.config
14
+
15
+ # Sobrescrever URL com a do settings
16
+ config.set_main_option("sqlalchemy.url", settings.database_url_sync)
17
+
18
+ if config.config_file_name is not None:
19
+ fileConfig(config.config_file_name)
20
+
21
+ target_metadata = Base.metadata
22
+
23
+
24
+ def run_migrations_offline() -> None:
25
+ """Roda migrations em modo 'offline'."""
26
+ url = config.get_main_option("sqlalchemy.url")
27
+ context.configure(
28
+ url=url,
29
+ target_metadata=target_metadata,
30
+ literal_binds=True,
31
+ dialect_opts={"paramstyle": "named"},
32
+ )
33
+
34
+ with context.begin_transaction():
35
+ context.run_migrations()
36
+
37
+
38
+ def run_migrations_online() -> None:
39
+ """Roda migrations em modo 'online'."""
40
+ connectable = engine_from_config(
41
+ config.get_section(config.config_ini_section, {}),
42
+ prefix="sqlalchemy.",
43
+ poolclass=pool.NullPool,
44
+ )
45
+
46
+ with connectable.connect() as connection:
47
+ context.configure(connection=connection, target_metadata=target_metadata)
48
+
49
+ with context.begin_transaction():
50
+ context.run_migrations()
51
+
52
+
53
+ if context.is_offline_mode():
54
+ run_migrations_offline()
55
+ else:
56
+ run_migrations_online()
@@ -0,0 +1,26 @@
1
+ """${message}
2
+
3
+ Revision ID: ${up_revision}
4
+ Revises: ${down_revision | comma,n}
5
+ Create Date: ${create_date}
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ ${imports if imports else ""}
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = ${repr(up_revision)}
16
+ down_revision: Union[str, None] = ${repr(down_revision)}
17
+ branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
+ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
+
20
+
21
+ def upgrade() -> None:
22
+ ${upgrades if upgrades else "pass"}
23
+
24
+
25
+ def downgrade() -> None:
26
+ ${downgrades if downgrades else "pass"}
File without changes