hinbert-fastapi 0.1.0__tar.gz → 0.2.0__tar.gz

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 (107) hide show
  1. hinbert_fastapi-0.2.0/PKG-INFO +322 -0
  2. hinbert_fastapi-0.2.0/README.md +284 -0
  3. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/deps/auth.py +40 -40
  4. hinbert_fastapi-0.2.0/app/core/middleware/__init__.py +14 -0
  5. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/security/auth.py +15 -8
  6. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/auth_service.py +32 -32
  7. hinbert_fastapi-0.2.0/hinbert_cli/__init__.py +0 -0
  8. hinbert_fastapi-0.2.0/hinbert_cli/main.py +1015 -0
  9. hinbert_fastapi-0.2.0/hinbert_fastapi.egg-info/PKG-INFO +322 -0
  10. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/hinbert_fastapi.egg-info/SOURCES.txt +2 -0
  11. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/hinbert_fastapi.egg-info/entry_points.txt +1 -1
  12. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/hinbert_fastapi.egg-info/top_level.txt +1 -0
  13. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/pyproject.toml +41 -41
  14. hinbert_fastapi-0.1.0/PKG-INFO +0 -0
  15. hinbert_fastapi-0.1.0/README.md +0 -0
  16. hinbert_fastapi-0.1.0/app/core/middleware/__init__.py +0 -1
  17. hinbert_fastapi-0.1.0/hinbert_fastapi.egg-info/PKG-INFO +0 -0
  18. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/LICENSE +0 -0
  19. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/__init__.py +0 -0
  20. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/__init__.py +0 -0
  21. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/deps/__init__.py +0 -0
  22. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/deps/pagination.py +0 -0
  23. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/__init__.py +0 -0
  24. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/endpoints/__init__.py +0 -0
  25. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/endpoints/auth.py +0 -0
  26. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/endpoints/dashboard.py +0 -0
  27. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/endpoints/products.py +0 -0
  28. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/endpoints/users.py +0 -0
  29. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/routers/__init__.py +0 -0
  30. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/api/v1/routers/api_router.py +0 -0
  31. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/__init__.py +0 -0
  32. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/config/__init__.py +0 -0
  33. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/config/database.py +0 -0
  34. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/config/settings.py +0 -0
  35. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/exceptions/__init__.py +0 -0
  36. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/exceptions/base_exception.py +0 -0
  37. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/exceptions/custom_exceptions.py +0 -0
  38. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/middleware/cors.py +0 -0
  39. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/middleware/error_handler.py +0 -0
  40. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/middleware/logging.py +0 -0
  41. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/middleware/rate_limit.py +0 -0
  42. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/security/__init__.py +0 -0
  43. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/security/jwt.py +0 -0
  44. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/security/oauth.py +0 -0
  45. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/security/password.py +0 -0
  46. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/core/security/totp.py +0 -0
  47. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/db/__init__.py +0 -0
  48. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/db/base.py +0 -0
  49. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/db/migrations/env.py +0 -0
  50. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/db/migrations/versions/97ed1bc05f4a_complete_product_and_totp_fields.py +0 -0
  51. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/db/migrations/versions/f8b632aa11da_initial_migration.py +0 -0
  52. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/db/session.py +0 -0
  53. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/main.py +0 -0
  54. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/__init__.py +0 -0
  55. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/__init__.py +0 -0
  56. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/base.py +0 -0
  57. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/email_verification.py +0 -0
  58. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/password_reset.py +0 -0
  59. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/product.py +0 -0
  60. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/refresh_token.py +0 -0
  61. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/totp_secret.py +0 -0
  62. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/domain/user.py +0 -0
  63. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/__init__.py +0 -0
  64. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/auth.py +0 -0
  65. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/password.py +0 -0
  66. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/product.py +0 -0
  67. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/response.py +0 -0
  68. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/token.py +0 -0
  69. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/totp.py +0 -0
  70. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/models/schemas/user.py +0 -0
  71. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/__init__.py +0 -0
  72. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/base/__init__.py +0 -0
  73. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/base/base_repository.py +0 -0
  74. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/email_verification_repository.py +0 -0
  75. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/password_reset_repository.py +0 -0
  76. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/product_repository.py +0 -0
  77. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/refresh_token_repository.py +0 -0
  78. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/totp_secret_repository.py +0 -0
  79. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/repositories/user_repository.py +0 -0
  80. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/__init__.py +0 -0
  81. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/base/__init__.py +0 -0
  82. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/base/base_service.py +0 -0
  83. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/email_service.py +0 -0
  84. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/product_service.py +0 -0
  85. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/social_auth_service.py +0 -0
  86. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/totp_service.py +0 -0
  87. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/services/user_service.py +0 -0
  88. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/__init__.py +0 -0
  89. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/conftest.py +0 -0
  90. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/integration/test_auth_api.py +0 -0
  91. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/integration/test_product_api.py +0 -0
  92. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/integration/test_user_api.py +0 -0
  93. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/unit/test_auth_service.py +0 -0
  94. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/unit/test_product_service.py +0 -0
  95. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/tests/unit/test_user_service.py +0 -0
  96. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/utils/__init__.py +0 -0
  97. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/utils/date_utils.py +0 -0
  98. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/utils/file_utils.py +0 -0
  99. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/utils/logger.py +0 -0
  100. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/app/utils/validators.py +0 -0
  101. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/hinbert_fastapi.egg-info/dependency_links.txt +0 -0
  102. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/hinbert_fastapi.egg-info/requires.txt +0 -0
  103. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/scripts/__init__.py +0 -0
  104. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/scripts/create_admin.py +0 -0
  105. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/scripts/run_migrations.py +0 -0
  106. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/scripts/seed_data.py +0 -0
  107. {hinbert_fastapi-0.1.0 → hinbert_fastapi-0.2.0}/setup.cfg +0 -0
@@ -0,0 +1,322 @@
1
+ Metadata-Version: 2.4
2
+ Name: hinbert-fastapi
3
+ Version: 0.2.0
4
+ Summary: Professional FastAPI boilerplate with JWT auth, 2FA, PostgreSQL, Docker
5
+ Author: Hinbert Engineering
6
+ License: MIT
7
+ Project-URL: Documentation, https://github.com/hinbert/hinbert-fastapi#readme
8
+ Project-URL: Repository, https://github.com/hinbert/hinbert-fastapi
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Framework :: FastAPI
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: fastapi<1,>=0.115
18
+ Requires-Dist: uvicorn[standard]<1,>=0.30
19
+ Requires-Dist: sqlalchemy[asyncio]<3,>=2.0
20
+ Requires-Dist: asyncpg<1,>=0.29
21
+ Requires-Dist: aiosqlite<1,>=0.20
22
+ Requires-Dist: alembic<2,>=1.13
23
+ Requires-Dist: pydantic<3,>=2.8
24
+ Requires-Dist: pydantic-settings<3,>=2.4
25
+ Requires-Dist: python-jose[cryptography]<4,>=3.3
26
+ Requires-Dist: passlib[bcrypt]<2,>=1.7
27
+ Requires-Dist: bcrypt<5,>=4.0
28
+ Requires-Dist: pyotp<3,>=2.9
29
+ Requires-Dist: slowapi<1,>=0.1.9
30
+ Requires-Dist: loguru<1,>=0.7
31
+ Requires-Dist: email-validator<3,>=2.2
32
+ Requires-Dist: python-multipart<1,>=0.0.9
33
+ Requires-Dist: redis<6,>=5
34
+ Requires-Dist: aiosmtplib<4,>=3
35
+ Requires-Dist: cryptography<46,>=42
36
+ Requires-Dist: httpx<1,>=0.27
37
+ Dynamic: license-file
38
+
39
+ # Hinbert FastAPI
40
+
41
+ A modern, production-oriented FastAPI backend foundation for secure web applications. Built for teams that want a clean architecture, strong authentication defaults, scalable API design, and quick deployment without starting from scratch.
42
+
43
+ ## Why this project?
44
+
45
+ Hinbert FastAPI combines a pragmatic backend structure with security-first design patterns:
46
+
47
+ - JWT-based authentication with refresh token rotation
48
+ - Password reset and email verification flows
49
+ - Optional TOTP multi-factor authentication
50
+ - OAuth login for Google and Facebook
51
+ - Async SQLAlchemy data layer with PostgreSQL support
52
+ - Rate limiting, request logging, and structured error handling
53
+ - Clean separation between API, services, repositories, and models
54
+ - Docker-ready local environment and deployment support
55
+
56
+ ## Features
57
+
58
+ - Secure user registration and login
59
+ - Email verification and password recovery
60
+ - Access token + refresh token issuance
61
+ - Logout and refresh-token revocation
62
+ - TOTP setup and validation
63
+ - Social authentication hooks
64
+ - Product CRUD endpoints with filtering, sorting, and pagination
65
+ - Redis-backed rate limiting
66
+ - Pydantic-based validation and environment configuration
67
+ - Alembic migrations for database evolution
68
+ - Python testing coverage for core business flows
69
+
70
+ ### Available Commands
71
+
72
+ | Command | Description | Example |
73
+ | --- | --- | --- |
74
+ | `hinbert init [PROJECT_NAME]` | Create a new FastAPI project | `hinbert init my_app` |
75
+ | `hinbert init --help` | Show help and available options | `hinbert init --help` |
76
+ | `hinbert init .` | Generate project in current directory | `hinbert init .` |
77
+ | `hinbert init [PROJECT_NAME] --yes` | Skip prompts, use defaults | `hinbert init my_app --yes` |
78
+ | `--db [postgresql|mysql|sqlite]` | Choose database | `--db postgresql` |
79
+ | `--auth [jwt|oauth2|none]` | Choose authentication | `--auth jwt` |
80
+ | `--no-2fa` | Skip two-factor authentication | `--no-2fa` |
81
+ | `--no-email` | Skip email verification | `--no-email` |
82
+ | `--no-rate-limit` | Skip rate limiting | `--no-rate-limit` |
83
+ | `--no-docker` | Skip Docker configuration | `--no-docker` |
84
+ | `--k8s` | Include Kubernetes/Helm | `--k8s` |
85
+ | `--logging [loguru|structlog|none]` | Choose logging library | `--logging structlog` |
86
+ | `-y, --yes` | Skip all confirmation prompts | `-y` |
87
+
88
+ ## Tech Stack
89
+
90
+ - Python 3.12+
91
+ - FastAPI
92
+ - SQLAlchemy 2 with async support
93
+ - PostgreSQL / SQLite compatibility
94
+ - Pydantic v2
95
+ - Redis
96
+ - Alembic
97
+ - JWT + bcrypt + pyotp
98
+ - Docker and Docker Compose
99
+ - pytest
100
+
101
+ ## Architecture
102
+
103
+ ```text
104
+ app/
105
+ ├── api/
106
+ │ ├── deps/
107
+ │ └── v1/
108
+ │ ├── endpoints/
109
+ │ └── routers/
110
+ ├── core/
111
+ │ ├── config/
112
+ │ ├── exceptions/
113
+ │ ├── middleware/
114
+ │ └── security/
115
+ ├── db/
116
+ │ └── migrations/
117
+ ├── models/
118
+ │ ├── domain/
119
+ │ └── schemas/
120
+ ├── repositories/
121
+ ├── services/
122
+ ├── tests/
123
+ ├── main.py
124
+ ├── __init__.py
125
+
126
+ scripts/
127
+ ├── create_admin.py
128
+ ├── run_migrations.py
129
+ ├── seed_data.py
130
+
131
+ docker/
132
+ ├── Dockerfile
133
+ ├── docker-compose.yml
134
+
135
+ alembic.ini
136
+ pyproject.toml
137
+ requirements.txt
138
+ requirements-dev.txt
139
+ .env.example
140
+ README.md
141
+ ```
142
+
143
+ ## Quick Start
144
+
145
+ ### Prerequisites
146
+
147
+ - Python 3.12+
148
+ - PostgreSQL or Docker
149
+ - Redis or Docker
150
+ - Git
151
+
152
+ ### 1. Clone the repository
153
+
154
+ ```bash
155
+ git clone <repository-url>
156
+ cd hinbert_fastapi
157
+ ```
158
+
159
+ ### 2. Create a virtual environment
160
+
161
+ ```bash
162
+ python -m venv .venv
163
+ ```
164
+
165
+ On Windows PowerShell:
166
+
167
+ ```powershell
168
+ .\.venv\Scripts\Activate.ps1
169
+ ```
170
+
171
+ On macOS/Linux:
172
+
173
+ ```bash
174
+ source .venv/bin/activate
175
+ ```
176
+
177
+ ### 3. Install dependencies
178
+
179
+ ```bash
180
+ pip install -r requirements.txt
181
+ pip install -r requirements-dev.txt
182
+ ```
183
+
184
+ ### 4. Configure environment variables
185
+
186
+ ```bash
187
+ copy .env.example .env
188
+ ```
189
+
190
+ or:
191
+
192
+ ```bash
193
+ cp .env.example .env
194
+ ```
195
+
196
+ Update the values in `.env` for your database, Redis, JWT secret, SMTP settings, and OAuth credentials.
197
+
198
+ ### 5. Run database migrations
199
+
200
+ ```bash
201
+ python -m scripts.run_migrations
202
+ ```
203
+
204
+ ### 6. Start the API
205
+
206
+ ```bash
207
+ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
208
+ ```
209
+
210
+ Once running, the app is available at:
211
+
212
+ - API: http://localhost:8000
213
+ - Swagger UI: http://localhost:8000/docs
214
+ - ReDoc: http://localhost:8000/redoc
215
+ - Health: http://localhost:8000/health
216
+
217
+ ## Docker Setup
218
+
219
+ This project includes a Docker Compose setup for local development.
220
+
221
+ ```bash
222
+ docker compose -f docker/docker-compose.yml up --build
223
+ ```
224
+
225
+ To stop it:
226
+
227
+ ```bash
228
+ docker compose -f docker/docker-compose.yml down
229
+ ```
230
+
231
+ ## API Highlights
232
+
233
+ The application exposes a versioned API under `/api/v1`.
234
+
235
+ ### Auth endpoints
236
+
237
+ - `/api/v1/auth/signup`
238
+ - `/api/v1/auth/login`
239
+ - `/api/v1/auth/refresh`
240
+ - `/api/v1/auth/logout`
241
+ - `/api/v1/auth/forgot-password`
242
+ - `/api/v1/auth/reset-password`
243
+ - `/api/v1/auth/totp/setup`
244
+ - `/api/v1/auth/totp/verify`
245
+ - `/api/v1/auth/google`
246
+ - `/api/v1/auth/facebook`
247
+
248
+ ### Product endpoints
249
+
250
+ - `/api/v1/products`
251
+ - `/api/v1/products/{product_id}`
252
+
253
+ ### User endpoints
254
+
255
+ - `/api/v1/users/me`
256
+ - admin/user management routes where applicable
257
+
258
+ ## Example Authentication Flow
259
+
260
+ ```json
261
+ {
262
+ "email": "user@example.com",
263
+ "password": "StrongPassword!123"
264
+ }
265
+ ```
266
+
267
+ The login response returns both an access token and refresh token:
268
+
269
+ ```http
270
+ Authorization: Bearer <access_token>
271
+ ```
272
+
273
+ ## Environment Configuration
274
+
275
+ The project reads configuration using Pydantic settings from `.env` and supports values such as:
276
+
277
+ - `DATABASE_URL`
278
+ - `REDIS_URL`
279
+ - `SECRET_KEY`
280
+ - `ALGORITHM`
281
+ - `ACCESS_TOKEN_EXPIRE_MINUTES`
282
+ - `REFRESH_TOKEN_EXPIRE_DAYS`
283
+ - `SMTP_HOST`
284
+ - `SMTP_PORT`
285
+ - `EMAIL_FROM`
286
+ - `GOOGLE_CLIENT_ID`
287
+ - `FACEBOOK_CLIENT_ID`
288
+ - `BACKEND_CORS_ORIGINS`
289
+
290
+ ## Testing
291
+
292
+ Run the test suite with:
293
+
294
+ ```bash
295
+ pytest
296
+ ```
297
+
298
+ Targeted test folders:
299
+
300
+ ```bash
301
+ pytest app/tests/unit
302
+ pytest app/tests/integration
303
+ ```
304
+
305
+ ## Security Notes
306
+
307
+ This project includes strong defaults for a starter backend, but production deployments should still:
308
+
309
+ - replace the default JWT secret with a secure secret manager value
310
+ - restrict CORS origins to trusted domains
311
+ - protect database credentials and infrastructure endpoints
312
+ - use HTTPS behind a reverse proxy or load balancer
313
+ - configure valid SMTP and OAuth provider credentials
314
+ - enable monitoring, backups, and secure deployment policies
315
+
316
+ ## Contributing
317
+
318
+ Contributions are welcome. Please keep pull requests focused, add or update tests for behavior changes, and keep code consistent with the existing project structure.
319
+
320
+ ## License
321
+
322
+ This project is licensed under the MIT License.
@@ -0,0 +1,284 @@
1
+ # Hinbert FastAPI
2
+
3
+ A modern, production-oriented FastAPI backend foundation for secure web applications. Built for teams that want a clean architecture, strong authentication defaults, scalable API design, and quick deployment without starting from scratch.
4
+
5
+ ## Why this project?
6
+
7
+ Hinbert FastAPI combines a pragmatic backend structure with security-first design patterns:
8
+
9
+ - JWT-based authentication with refresh token rotation
10
+ - Password reset and email verification flows
11
+ - Optional TOTP multi-factor authentication
12
+ - OAuth login for Google and Facebook
13
+ - Async SQLAlchemy data layer with PostgreSQL support
14
+ - Rate limiting, request logging, and structured error handling
15
+ - Clean separation between API, services, repositories, and models
16
+ - Docker-ready local environment and deployment support
17
+
18
+ ## Features
19
+
20
+ - Secure user registration and login
21
+ - Email verification and password recovery
22
+ - Access token + refresh token issuance
23
+ - Logout and refresh-token revocation
24
+ - TOTP setup and validation
25
+ - Social authentication hooks
26
+ - Product CRUD endpoints with filtering, sorting, and pagination
27
+ - Redis-backed rate limiting
28
+ - Pydantic-based validation and environment configuration
29
+ - Alembic migrations for database evolution
30
+ - Python testing coverage for core business flows
31
+
32
+ ### Available Commands
33
+
34
+ | Command | Description | Example |
35
+ | --- | --- | --- |
36
+ | `hinbert init [PROJECT_NAME]` | Create a new FastAPI project | `hinbert init my_app` |
37
+ | `hinbert init --help` | Show help and available options | `hinbert init --help` |
38
+ | `hinbert init .` | Generate project in current directory | `hinbert init .` |
39
+ | `hinbert init [PROJECT_NAME] --yes` | Skip prompts, use defaults | `hinbert init my_app --yes` |
40
+ | `--db [postgresql|mysql|sqlite]` | Choose database | `--db postgresql` |
41
+ | `--auth [jwt|oauth2|none]` | Choose authentication | `--auth jwt` |
42
+ | `--no-2fa` | Skip two-factor authentication | `--no-2fa` |
43
+ | `--no-email` | Skip email verification | `--no-email` |
44
+ | `--no-rate-limit` | Skip rate limiting | `--no-rate-limit` |
45
+ | `--no-docker` | Skip Docker configuration | `--no-docker` |
46
+ | `--k8s` | Include Kubernetes/Helm | `--k8s` |
47
+ | `--logging [loguru|structlog|none]` | Choose logging library | `--logging structlog` |
48
+ | `-y, --yes` | Skip all confirmation prompts | `-y` |
49
+
50
+ ## Tech Stack
51
+
52
+ - Python 3.12+
53
+ - FastAPI
54
+ - SQLAlchemy 2 with async support
55
+ - PostgreSQL / SQLite compatibility
56
+ - Pydantic v2
57
+ - Redis
58
+ - Alembic
59
+ - JWT + bcrypt + pyotp
60
+ - Docker and Docker Compose
61
+ - pytest
62
+
63
+ ## Architecture
64
+
65
+ ```text
66
+ app/
67
+ ├── api/
68
+ │ ├── deps/
69
+ │ └── v1/
70
+ │ ├── endpoints/
71
+ │ └── routers/
72
+ ├── core/
73
+ │ ├── config/
74
+ │ ├── exceptions/
75
+ │ ├── middleware/
76
+ │ └── security/
77
+ ├── db/
78
+ │ └── migrations/
79
+ ├── models/
80
+ │ ├── domain/
81
+ │ └── schemas/
82
+ ├── repositories/
83
+ ├── services/
84
+ ├── tests/
85
+ ├── main.py
86
+ ├── __init__.py
87
+
88
+ scripts/
89
+ ├── create_admin.py
90
+ ├── run_migrations.py
91
+ ├── seed_data.py
92
+
93
+ docker/
94
+ ├── Dockerfile
95
+ ├── docker-compose.yml
96
+
97
+ alembic.ini
98
+ pyproject.toml
99
+ requirements.txt
100
+ requirements-dev.txt
101
+ .env.example
102
+ README.md
103
+ ```
104
+
105
+ ## Quick Start
106
+
107
+ ### Prerequisites
108
+
109
+ - Python 3.12+
110
+ - PostgreSQL or Docker
111
+ - Redis or Docker
112
+ - Git
113
+
114
+ ### 1. Clone the repository
115
+
116
+ ```bash
117
+ git clone <repository-url>
118
+ cd hinbert_fastapi
119
+ ```
120
+
121
+ ### 2. Create a virtual environment
122
+
123
+ ```bash
124
+ python -m venv .venv
125
+ ```
126
+
127
+ On Windows PowerShell:
128
+
129
+ ```powershell
130
+ .\.venv\Scripts\Activate.ps1
131
+ ```
132
+
133
+ On macOS/Linux:
134
+
135
+ ```bash
136
+ source .venv/bin/activate
137
+ ```
138
+
139
+ ### 3. Install dependencies
140
+
141
+ ```bash
142
+ pip install -r requirements.txt
143
+ pip install -r requirements-dev.txt
144
+ ```
145
+
146
+ ### 4. Configure environment variables
147
+
148
+ ```bash
149
+ copy .env.example .env
150
+ ```
151
+
152
+ or:
153
+
154
+ ```bash
155
+ cp .env.example .env
156
+ ```
157
+
158
+ Update the values in `.env` for your database, Redis, JWT secret, SMTP settings, and OAuth credentials.
159
+
160
+ ### 5. Run database migrations
161
+
162
+ ```bash
163
+ python -m scripts.run_migrations
164
+ ```
165
+
166
+ ### 6. Start the API
167
+
168
+ ```bash
169
+ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
170
+ ```
171
+
172
+ Once running, the app is available at:
173
+
174
+ - API: http://localhost:8000
175
+ - Swagger UI: http://localhost:8000/docs
176
+ - ReDoc: http://localhost:8000/redoc
177
+ - Health: http://localhost:8000/health
178
+
179
+ ## Docker Setup
180
+
181
+ This project includes a Docker Compose setup for local development.
182
+
183
+ ```bash
184
+ docker compose -f docker/docker-compose.yml up --build
185
+ ```
186
+
187
+ To stop it:
188
+
189
+ ```bash
190
+ docker compose -f docker/docker-compose.yml down
191
+ ```
192
+
193
+ ## API Highlights
194
+
195
+ The application exposes a versioned API under `/api/v1`.
196
+
197
+ ### Auth endpoints
198
+
199
+ - `/api/v1/auth/signup`
200
+ - `/api/v1/auth/login`
201
+ - `/api/v1/auth/refresh`
202
+ - `/api/v1/auth/logout`
203
+ - `/api/v1/auth/forgot-password`
204
+ - `/api/v1/auth/reset-password`
205
+ - `/api/v1/auth/totp/setup`
206
+ - `/api/v1/auth/totp/verify`
207
+ - `/api/v1/auth/google`
208
+ - `/api/v1/auth/facebook`
209
+
210
+ ### Product endpoints
211
+
212
+ - `/api/v1/products`
213
+ - `/api/v1/products/{product_id}`
214
+
215
+ ### User endpoints
216
+
217
+ - `/api/v1/users/me`
218
+ - admin/user management routes where applicable
219
+
220
+ ## Example Authentication Flow
221
+
222
+ ```json
223
+ {
224
+ "email": "user@example.com",
225
+ "password": "StrongPassword!123"
226
+ }
227
+ ```
228
+
229
+ The login response returns both an access token and refresh token:
230
+
231
+ ```http
232
+ Authorization: Bearer <access_token>
233
+ ```
234
+
235
+ ## Environment Configuration
236
+
237
+ The project reads configuration using Pydantic settings from `.env` and supports values such as:
238
+
239
+ - `DATABASE_URL`
240
+ - `REDIS_URL`
241
+ - `SECRET_KEY`
242
+ - `ALGORITHM`
243
+ - `ACCESS_TOKEN_EXPIRE_MINUTES`
244
+ - `REFRESH_TOKEN_EXPIRE_DAYS`
245
+ - `SMTP_HOST`
246
+ - `SMTP_PORT`
247
+ - `EMAIL_FROM`
248
+ - `GOOGLE_CLIENT_ID`
249
+ - `FACEBOOK_CLIENT_ID`
250
+ - `BACKEND_CORS_ORIGINS`
251
+
252
+ ## Testing
253
+
254
+ Run the test suite with:
255
+
256
+ ```bash
257
+ pytest
258
+ ```
259
+
260
+ Targeted test folders:
261
+
262
+ ```bash
263
+ pytest app/tests/unit
264
+ pytest app/tests/integration
265
+ ```
266
+
267
+ ## Security Notes
268
+
269
+ This project includes strong defaults for a starter backend, but production deployments should still:
270
+
271
+ - replace the default JWT secret with a secure secret manager value
272
+ - restrict CORS origins to trusted domains
273
+ - protect database credentials and infrastructure endpoints
274
+ - use HTTPS behind a reverse proxy or load balancer
275
+ - configure valid SMTP and OAuth provider credentials
276
+ - enable monitoring, backups, and secure deployment policies
277
+
278
+ ## Contributing
279
+
280
+ Contributions are welcome. Please keep pull requests focused, add or update tests for behavior changes, and keep code consistent with the existing project structure.
281
+
282
+ ## License
283
+
284
+ This project is licensed under the MIT License.
@@ -1,40 +1,40 @@
1
- """Bearer-token dependencies for protected routes."""
2
-
3
- from uuid import UUID
4
-
5
- from fastapi import Depends
6
- from fastapi.security import OAuth2PasswordBearer
7
- from sqlalchemy.ext.asyncio import AsyncSession
8
-
9
- from app.core.exceptions.custom_exceptions import UnauthorizedError
10
- from app.core.security.jwt import decode_token
11
- from app.db.session import get_db
12
- from app.models.domain.user import User
13
-
14
- oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")
15
-
16
-
17
- async def get_current_user(token: str = Depends(oauth2_scheme), session: AsyncSession = Depends(get_db)) -> User:
18
- """Decode an access token and load its user, failing closed on any error."""
19
- try:
20
- subject = UUID(decode_token(token)["sub"])
21
- except (ValueError, KeyError) as exc:
22
- raise UnauthorizedError() from exc
23
- user = await session.get(User, subject)
24
- if user is None:
25
- raise UnauthorizedError()
26
- return user
27
-
28
-
29
- async def get_current_active_user(user: User = Depends(get_current_user)) -> User:
30
- """Reject deactivated accounts before protected business operations."""
31
- if not user.is_active:
32
- raise UnauthorizedError("Inactive account")
33
- return user
34
-
35
-
36
- async def get_current_admin(user: User = Depends(get_current_active_user)) -> User:
37
- """Require an active account with administrator privileges."""
38
- if not user.is_admin:
39
- raise UnauthorizedError("Administrator privileges required")
40
- return user
1
+ """Bearer-token dependencies for protected routes."""
2
+
3
+ from uuid import UUID
4
+
5
+ from fastapi import Depends
6
+ from fastapi.security import OAuth2PasswordBearer
7
+ from sqlalchemy.ext.asyncio import AsyncSession
8
+
9
+ from app.core.exceptions.custom_exceptions import UnauthorizedError
10
+ from app.core.security.auth import decode_token
11
+ from app.db.session import get_db
12
+ from app.models.domain.user import User
13
+
14
+ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")
15
+
16
+
17
+ async def get_current_user(token: str = Depends(oauth2_scheme), session: AsyncSession = Depends(get_db)) -> User:
18
+ """Decode an access token and load its user, failing closed on any error."""
19
+ try:
20
+ subject = UUID(decode_token(token)["sub"])
21
+ except (ValueError, KeyError) as exc:
22
+ raise UnauthorizedError() from exc
23
+ user = await session.get(User, subject)
24
+ if user is None:
25
+ raise UnauthorizedError()
26
+ return user
27
+
28
+
29
+ async def get_current_active_user(user: User = Depends(get_current_user)) -> User:
30
+ """Reject deactivated accounts before protected business operations."""
31
+ if not user.is_active:
32
+ raise UnauthorizedError("Inactive account")
33
+ return user
34
+
35
+
36
+ async def get_current_admin(user: User = Depends(get_current_active_user)) -> User:
37
+ """Require an active account with administrator privileges."""
38
+ if not user.is_admin:
39
+ raise UnauthorizedError("Administrator privileges required")
40
+ return user
@@ -0,0 +1,14 @@
1
+ """HTTP middleware and exception handling components."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+
6
+
7
+ def generate_init_files(project_path):
8
+ for root, dirs, files in os.walk(project_path / "app"):
9
+ existing_modules = [f[:-3] for f in files if f.endswith('.py') and f != '__init__.py']
10
+ init_path = Path(root) / "__init__.py"
11
+ if existing_modules:
12
+ init_path.write_text("\n".join([f"from . import {m}" for m in existing_modules]))
13
+ else:
14
+ init_path.touch()