tempest-fastapi-sdk 0.35.0__tar.gz → 0.37.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.
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/CHANGELOG.md +119 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/PKG-INFO +27 -8
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/README.md +20 -7
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/installation.en.md +13 -2
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/installation.md +13 -2
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/admin.en.md +27 -5
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/admin.md +27 -5
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/cli.en.md +15 -3
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/cli.md +15 -3
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/uploads.en.md +1 -1
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/reference.md +10 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/roadmap.en.md +17 -2
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/roadmap.md +17 -2
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/pyproject.toml +12 -1
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/__init__.py +1 -1
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/admin/auth.py +85 -1
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/admin/config.py +31 -0
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/forms.py +363 -0
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/router.py +1492 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/admin/session.py +17 -1
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/static/admin.css +642 -0
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/templates/dashboard.html +47 -0
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/templates/detail.html +44 -0
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/templates/form.html +53 -0
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/templates/list.html +110 -0
- tempest_fastapi_sdk-0.37.0/tempest_fastapi_sdk/admin/templates/mfa.html +20 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +5 -1
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/docker_compose.py +39 -13
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/generate.py +1 -1
- tempest_fastapi_sdk-0.37.0/tests/admin/test_forms.py +98 -0
- tempest_fastapi_sdk-0.37.0/tests/admin/test_mfa.py +170 -0
- tempest_fastapi_sdk-0.37.0/tests/admin/test_router.py +919 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cli/test_docker_compose.py +31 -3
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cli/test_main.py +17 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/uv.lock +62 -2
- tempest_fastapi_sdk-0.35.0/tempest_fastapi_sdk/admin/router.py +0 -598
- tempest_fastapi_sdk-0.35.0/tempest_fastapi_sdk/admin/static/admin.css +0 -245
- tempest_fastapi_sdk-0.35.0/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -28
- tempest_fastapi_sdk-0.35.0/tempest_fastapi_sdk/admin/templates/detail.html +0 -18
- tempest_fastapi_sdk-0.35.0/tempest_fastapi_sdk/admin/templates/list.html +0 -62
- tempest_fastapi_sdk-0.35.0/tests/admin/test_router.py +0 -213
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/.github/workflows/ci.yml +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/.github/workflows/docs.yml +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/.github/workflows/release-pypi.yml +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/.gitignore +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/.python-version +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/CLAUDE.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/Makefile +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/architecture.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/architecture.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/changelog.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/changelog.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/contributing.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/contributing.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/index.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/index.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/index.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/index.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/api.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/api.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/business-rules.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/business-rules.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/domain.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/domain.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/flows.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/flows.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/index.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/learning/marketplace/index.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/migration.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/migration.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/auth-flow.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/auth-flow.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/br-helpers.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/br-helpers.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/cache.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/cache.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/database.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/database.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/http.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/http.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/idempotency.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/idempotency.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/index.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/index.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/logging.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/logging.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/metrics.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/metrics.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/mfa.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/mfa.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/queue-tasks.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/queue-tasks.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/realtime.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/realtime.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/security.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/security.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/sessions.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/sessions.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/storage.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/storage.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/testing.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/testing.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/uploads.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/websocket.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/recipes/websocket.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/reference.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/tutorial.en.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/docs/tutorial.md +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/mkdocs.yml +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/scripts/extract_recipe.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/admin/site.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/dependencies/auth.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/server.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/static.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/router.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/service.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/templates/activation.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/templates/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/templates/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/templates/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/templates/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/templates/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/auth/templates/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/db.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/main.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/new.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/cli/user.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/controllers/base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/core/context.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/core/enums.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/core/logging.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/connection.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/model.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/repository.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/py.typed +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/services/base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/settings/base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/settings/mixins.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/testing/database.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/download.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/email.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/log.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/password.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/admin/test_auth.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/admin/test_site.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/admin/test_user_model.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_body_size.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_cookies.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_cors.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_csrf.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_dependencies_auth.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_handlers.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_health_router.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_idempotency.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_jwt_dependency.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_logs_router.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_oauth.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_prometheus.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_request_id_middleware.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_role_dependency.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_server.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_static.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_webhooks.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/api/test_webhooks_rsa.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/auth/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/auth/test_service.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cache/test_decorator.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cache/test_redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cli/test_db.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cli/test_generate.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/cli/test_user.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/conftest.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/controllers/test_base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/core/test_context.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/core/test_enums.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/core/test_logging.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/test_alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/test_bulk_ops.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/test_connection.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/test_migrations.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/test_model.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/db/test_repository.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/exceptions/test_exceptions.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/queue/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/schemas/test_base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/schemas/test_cursor_pagination.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/schemas/test_link_headers.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/schemas/test_pagination.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/schemas/test_response.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/services/test_base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/sessions/test_sessions.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/settings/test_base.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/settings/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/sse/test_event_stream.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/storage/test_minio_client.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/tasks/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/tasks/test_scheduler.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/testing/test_database.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_client_ip.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_datetime.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_dict.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_download.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_email.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_http_client.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_jwt.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_lazy_extras.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_log.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_metrics.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_password.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_regex.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_throttle.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/utils/test_upload.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/webpush/test_dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/webpush/test_schemas.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.35.0 → tempest_fastapi_sdk-0.37.0}/tests/websockets/test_hub_and_router.py +0 -0
|
@@ -5,6 +5,125 @@ All notable changes to **tempest-fastapi-sdk** are listed below.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.37.0] — 2026-06-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`[sqlite]` and `[postgres]` install extras** for the async database
|
|
13
|
+
drivers. The SDK keeps `sqlalchemy[asyncio]` as a core dependency but
|
|
14
|
+
ships **no DBAPI driver by default** — the driver is a deploy choice.
|
|
15
|
+
Install `tempest-fastapi-sdk[sqlite]` (`aiosqlite`, dev default) or
|
|
16
|
+
`[postgres]` (`asyncpg`, production); both are bundled into `[all]`.
|
|
17
|
+
Without one, the engine raised `ModuleNotFoundError` on first
|
|
18
|
+
connection.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **`tempest new` scaffold now ships a working DB driver.** The generated
|
|
23
|
+
`pyproject.toml` pins `aiosqlite` as a **runtime** dependency (it was
|
|
24
|
+
previously dev-only, so the default SQLite URL failed under a no-dev
|
|
25
|
+
install) and carries a commented `asyncpg` line next to it, ready to
|
|
26
|
+
uncomment when switching `DATABASE_URL` to PostgreSQL — matching the
|
|
27
|
+
commented Postgres URL already in `.env.example`.
|
|
28
|
+
|
|
29
|
+
- **`tempest new` / `tempest generate --docker`: credentials now resolve
|
|
30
|
+
from `.env`, not hardcoded in the compose.** Every `environment:` block
|
|
31
|
+
in the generated `docker-compose.yaml` now uses the `${VAR:-default}`
|
|
32
|
+
form so Docker Compose reads the value from the `.env` next to the
|
|
33
|
+
compose file, keeping secrets out of a VCS-tracked compose. The
|
|
34
|
+
`:-default` preserves zero-config dev boot before `.env.example` is
|
|
35
|
+
copied to `.env`. Affected variables: `POSTGRES_USER` /
|
|
36
|
+
`POSTGRES_PASSWORD` / `POSTGRES_DB`, `RABBITMQ_DEFAULT_USER` /
|
|
37
|
+
`RABBITMQ_DEFAULT_PASS` / `RABBITMQ_DEFAULT_VHOST`, `MINIO_ROOT_USER` /
|
|
38
|
+
`MINIO_ROOT_PASSWORD` (plus the MinIO bootstrap container's `mc alias`).
|
|
39
|
+
`env_block_for` now emits these credential keys into `.env.example` so
|
|
40
|
+
the generated `.env` carries them with their defaults.
|
|
41
|
+
|
|
42
|
+
## [0.36.0] — 2026-06-06
|
|
43
|
+
|
|
44
|
+
Admin panel brought to Django-admin parity: the list view, write CRUD,
|
|
45
|
+
bulk actions, dashboard, login, and audit trail all landed across the
|
|
46
|
+
phases below.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **Admin list view — Phase 1 (read-only enhancements + responsive).**
|
|
51
|
+
- Clickable **column sorting** on the list view
|
|
52
|
+
(`?sort=<column>&dir=asc|desc`), validated against the displayed
|
|
53
|
+
real columns; the admin's configured `ordering` remains the
|
|
54
|
+
default.
|
|
55
|
+
- **CSV / JSON export** endpoint
|
|
56
|
+
(`GET /admin/m/{slug}/export.csv` / `.json`) honoring the active
|
|
57
|
+
search / filters / sort. New `make_admin_router(export_max_rows=…)`
|
|
58
|
+
caps export size (default 5000).
|
|
59
|
+
- **Responsive admin UI** — bundled templates + CSS now adapt to
|
|
60
|
+
mobile (≤600px): stacked header, full-width search/filters/actions,
|
|
61
|
+
horizontal-scroll table wrappers, single-column detail grid.
|
|
62
|
+
Verified at 390px (mobile) and 1280px (desktop).
|
|
63
|
+
|
|
64
|
+
- **Admin write CRUD — Phase 2a (create / edit / delete).**
|
|
65
|
+
- `GET/POST /admin/m/{slug}/new` (create), `GET/POST
|
|
66
|
+
/admin/m/{slug}/{identity}/edit` (edit), and `POST
|
|
67
|
+
/admin/m/{slug}/{identity}/delete` (delete), each gated by new
|
|
68
|
+
`AdminModel(can_create=…, can_edit=…, can_delete=…)` flags
|
|
69
|
+
(default `True`; a disabled view returns `404`).
|
|
70
|
+
- **CSRF-protected** mutations — every write form carries the
|
|
71
|
+
session CSRF token, verified server-side (`403` on mismatch).
|
|
72
|
+
- **Type-aware field widgets** — text / textarea (long strings) /
|
|
73
|
+
number / checkbox / `datetime-local` / date / enum `select`,
|
|
74
|
+
derived from the column types, with required-field + per-field
|
|
75
|
+
validation errors re-rendered on the form, and integrity errors
|
|
76
|
+
surfaced inline.
|
|
77
|
+
- Detail view gains Edit / Delete controls; list view gains a
|
|
78
|
+
"+ New" button. All responsive (verified at 390px / 1280px).
|
|
79
|
+
|
|
80
|
+
- **Admin bulk actions — Phase 2b.**
|
|
81
|
+
- List view gains row checkboxes + a select-all toggle and a bulk
|
|
82
|
+
action bar. `POST /admin/m/{slug}/bulk` applies **delete**
|
|
83
|
+
(`can_delete`), **activate** / **deactivate** (`can_edit`, toggling
|
|
84
|
+
the `is_active` flag) to the selected rows, CSRF-verified.
|
|
85
|
+
Backed by `BaseRepository.delete_batch` / `bulk_update`.
|
|
86
|
+
Responsive (verified at 390px / 1280px).
|
|
87
|
+
|
|
88
|
+
- **Admin foreign-key select — Phase 2c.**
|
|
89
|
+
- A foreign-key column whose referenced table has its own
|
|
90
|
+
`AdminModel` now renders as a **dropdown of the related rows**
|
|
91
|
+
(Django's FK select) on the create/edit form, instead of a raw
|
|
92
|
+
UUID input. Option labels come from the referenced admin's first
|
|
93
|
+
`search_fields` entry (falling back to a `name`/`title`/`email`
|
|
94
|
+
attribute, then the id). Capped at 1000 rows. FKs to unmanaged
|
|
95
|
+
tables stay plain UUID inputs.
|
|
96
|
+
|
|
97
|
+
- **Admin dashboard — counts + metrics (Phase 3a).**
|
|
98
|
+
- The dashboard now renders each registered model as a card with its
|
|
99
|
+
**live row count** and Browse / + New links, plus a **system
|
|
100
|
+
metrics panel** (CPU / RAM / disk) via `MetricsUtils`. The panel
|
|
101
|
+
is on by default, silently omitted when the `[metrics]` extra is
|
|
102
|
+
absent, and disabled with `make_admin_router(show_metrics=False)`.
|
|
103
|
+
Responsive card grids (verified at 390px / 1280px).
|
|
104
|
+
|
|
105
|
+
- **Admin MFA login — Phase 3b.**
|
|
106
|
+
- The admin login now supports a TOTP second factor. After the
|
|
107
|
+
password step, a principal with MFA enabled gets a short
|
|
108
|
+
`mfa_pending` session and is redirected to `GET/POST /admin/mfa`
|
|
109
|
+
(a CSRF-protected TOTP challenge); only a valid code upgrades the
|
|
110
|
+
session to full access. `AdminAuthBackend` gains `mfa_enabled` /
|
|
111
|
+
`verify_mfa` (default off); `UserModelAuthBackend` implements them
|
|
112
|
+
against `MFAMixin`'s `totp_secret` / `totp_enabled_at` via
|
|
113
|
+
`TOTPHelper` (new `mfa_issuer` / `mfa_window` ctor args). Pending
|
|
114
|
+
sessions are denied every admin page until the challenge passes.
|
|
115
|
+
|
|
116
|
+
- **Admin audit trail — Phase 3c.**
|
|
117
|
+
- Create/edit through the admin now **stamps** `created_by` /
|
|
118
|
+
`updated_by` (from `AuditMixin`) with the acting admin's id. The
|
|
119
|
+
detail view gained an **Audit panel** showing created/updated
|
|
120
|
+
timestamps and — when the model has the audit columns — the actor,
|
|
121
|
+
with the stored UUID resolved to a display name via the auth
|
|
122
|
+
backend. Models without `AuditMixin` show the timestamps only.
|
|
123
|
+
|
|
124
|
+
File-upload widget and inline/related editing remain tracked as later
|
|
125
|
+
admin phases on the roadmap.
|
|
126
|
+
|
|
8
127
|
## [0.35.0] — 2026-06-06
|
|
9
128
|
|
|
10
129
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tempest-fastapi-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.37.0
|
|
4
4
|
Summary: Shared FastAPI building blocks: base schemas, ORM model, async repository, exceptions, pagination and settings — the conventions used across Tempest projects.
|
|
5
5
|
Project-URL: Homepage, https://github.com/mauriciobenjamin700/tempest-fastapi-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/mauriciobenjamin700/tempest-fastapi-sdk
|
|
@@ -32,6 +32,8 @@ Requires-Dist: jinja2>=3.1.0; extra == 'admin'
|
|
|
32
32
|
Provides-Extra: all
|
|
33
33
|
Requires-Dist: aiofiles>=24.1.0; extra == 'all'
|
|
34
34
|
Requires-Dist: aiosmtplib>=4.0.0; extra == 'all'
|
|
35
|
+
Requires-Dist: aiosqlite>=0.20.0; extra == 'all'
|
|
36
|
+
Requires-Dist: asyncpg>=0.30.0; extra == 'all'
|
|
35
37
|
Requires-Dist: bcrypt>=5.0.0; extra == 'all'
|
|
36
38
|
Requires-Dist: cryptography>=42.0.0; extra == 'all'
|
|
37
39
|
Requires-Dist: email-validator>=2.0.0; extra == 'all'
|
|
@@ -68,10 +70,14 @@ Provides-Extra: mfa
|
|
|
68
70
|
Requires-Dist: pyotp>=2.9.0; extra == 'mfa'
|
|
69
71
|
Provides-Extra: minio
|
|
70
72
|
Requires-Dist: minio>=7.2.0; extra == 'minio'
|
|
73
|
+
Provides-Extra: postgres
|
|
74
|
+
Requires-Dist: asyncpg>=0.30.0; extra == 'postgres'
|
|
71
75
|
Provides-Extra: prometheus
|
|
72
76
|
Requires-Dist: prometheus-client>=0.20.0; extra == 'prometheus'
|
|
73
77
|
Provides-Extra: queue
|
|
74
78
|
Requires-Dist: faststream[rabbit]>=0.5.30; extra == 'queue'
|
|
79
|
+
Provides-Extra: sqlite
|
|
80
|
+
Requires-Dist: aiosqlite>=0.20.0; extra == 'sqlite'
|
|
75
81
|
Provides-Extra: tasks
|
|
76
82
|
Requires-Dist: taskiq-aio-pika>=0.4.0; extra == 'tasks'
|
|
77
83
|
Requires-Dist: taskiq>=0.11.0; extra == 'tasks'
|
|
@@ -174,7 +180,7 @@ Via `pyproject.toml`:
|
|
|
174
180
|
|
|
175
181
|
```toml
|
|
176
182
|
dependencies = [
|
|
177
|
-
"tempest-fastapi-sdk>=0.
|
|
183
|
+
"tempest-fastapi-sdk>=0.37.0",
|
|
178
184
|
]
|
|
179
185
|
```
|
|
180
186
|
|
|
@@ -199,13 +205,18 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
199
205
|
| `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
|
|
200
206
|
| `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
|
|
201
207
|
| `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
|
|
208
|
+
| `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
|
|
209
|
+
| `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
|
|
202
210
|
| `[all]` | everything above | every helper |
|
|
203
211
|
|
|
204
212
|
```bash
|
|
205
213
|
pip install "tempest-fastapi-sdk[auth,upload]" # only what the service uses
|
|
206
|
-
pip install "tempest-fastapi-sdk[
|
|
214
|
+
pip install "tempest-fastapi-sdk[postgres]" # add the async DB driver you deploy with
|
|
215
|
+
pip install "tempest-fastapi-sdk[all]" # or pull everything
|
|
207
216
|
```
|
|
208
217
|
|
|
218
|
+
> **The SDK ships no database driver by default.** `sqlalchemy[asyncio]` is core, but the async DBAPI is your deploy choice — add `[sqlite]` (`aiosqlite`, dev default) or `[postgres]` (`asyncpg`, production). Without one, the engine raises `ModuleNotFoundError` for the driver on first connection. Services scaffolded with `tempest new` already pin `aiosqlite` and carry a commented `asyncpg` line in `pyproject.toml`.
|
|
219
|
+
|
|
209
220
|
Since `0.7.1` every optional dependency is imported lazily at first instantiation, so `import tempest_fastapi_sdk` works with any subset of extras — instantiating a helper whose extra is missing raises `ImportError` with a clear hint pointing at the right one.
|
|
210
221
|
|
|
211
222
|
---
|
|
@@ -3403,7 +3414,7 @@ tempest user list --admin # admins only
|
|
|
3403
3414
|
|
|
3404
3415
|
### Admin site recipe
|
|
3405
3416
|
|
|
3406
|
-
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks.
|
|
3417
|
+
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks. The panel is feature-complete (Django-admin parity): a list view with search / per-field filters / sortable columns, full CRUD (create / edit / delete), bulk actions, CSV/JSON export, FK-select widgets, a dashboard with live row counts + system metrics, optional TOTP MFA at login, and an audit trail stamping `created_by` / `updated_by`. Still on the roadmap: file upload and inline/related editing.
|
|
3407
3418
|
|
|
3408
3419
|
Requires the `[admin]` extra:
|
|
3409
3420
|
|
|
@@ -3522,11 +3533,19 @@ app.include_router(
|
|
|
3522
3533
|
`make_admin_router` mounts:
|
|
3523
3534
|
|
|
3524
3535
|
- `GET /admin/login`, `POST /admin/login`, `POST /admin/logout` — auth flow.
|
|
3525
|
-
- `GET
|
|
3526
|
-
- `GET /admin
|
|
3527
|
-
- `GET /admin/m/{slug}
|
|
3536
|
+
- `GET/POST /admin/mfa` — TOTP challenge (second factor) between password and access, for principals with MFA enabled.
|
|
3537
|
+
- `GET /admin/` — dashboard: a card per model with **row count** + Browse/New, plus a **metrics panel** (CPU/RAM/disk via `MetricsUtils`; on by default, omitted without the `[metrics]` extra, disabled with `make_admin_router(show_metrics=False)`).
|
|
3538
|
+
- `GET /admin/m/{slug}/` — list view with pagination + free-text search (`?q=`) + per-field filters (`?filter_<field>=value`) + clickable **column sorting** (`?sort=<column>&dir=asc|desc`).
|
|
3539
|
+
- `GET /admin/m/{slug}/export.csv` / `export.json` — **export** the current result set (honoring search/filters/sort) as CSV or JSON (row cap via `make_admin_router(export_max_rows=…)`, default 5000).
|
|
3540
|
+
- `POST /admin/m/{slug}/bulk` — **bulk actions** (delete / activate / deactivate) on selected rows.
|
|
3541
|
+
- `GET/POST /admin/m/{slug}/new` — **create** a record (when `can_create`).
|
|
3542
|
+
- `GET /admin/m/{slug}/{identity}` — detail view with Edit/Delete buttons + an Audit panel.
|
|
3543
|
+
- `GET/POST /admin/m/{slug}/{identity}/edit` — **edit** a record (when `can_edit`).
|
|
3544
|
+
- `POST /admin/m/{slug}/{identity}/delete` — **delete** a record (when `can_delete`).
|
|
3528
3545
|
- `GET /admin/static/{path}` — bundled CSS/HTMX assets.
|
|
3529
3546
|
|
|
3547
|
+
Write operations (create/edit/delete/bulk) are gated by the `AdminModel` flags `can_create` / `can_edit` / `can_delete` (all `True` by default; a disabled view returns `404`), carry a per-session CSRF token validated server-side, derive form widgets from the column type, render an FK-select dropdown for foreign keys whose target has a registered `AdminModel`, and stamp `created_by` / `updated_by` (from `AuditMixin`) with the acting admin's id.
|
|
3548
|
+
|
|
3530
3549
|
#### 4. Session security defaults
|
|
3531
3550
|
|
|
3532
3551
|
`SignedCookieSessionStore` uses `itsdangerous.TimestampSigner` (HMAC-SHA256) to sign a single cookie:
|
|
@@ -3535,7 +3554,7 @@ app.include_router(
|
|
|
3535
3554
|
- `Secure` flagged when `cookie_secure=True` (default; flip off in local HTTP dev).
|
|
3536
3555
|
- `SameSite=Lax` (`"lax"`/`"strict"`/`"none"` accepted).
|
|
3537
3556
|
- Default lifetime `8h`; expired or tampered cookies are rejected silently.
|
|
3538
|
-
- Per-session CSRF token is generated at login and required by every form POST (
|
|
3557
|
+
- Per-session CSRF token is generated at login and required by every form POST (login, logout, create, edit, delete, bulk actions).
|
|
3539
3558
|
- `secret_key` must be at least 32 bytes — short keys raise `ValueError` at construction time.
|
|
3540
3559
|
|
|
3541
3560
|
#### 5. Plug in a custom auth backend
|
|
@@ -89,7 +89,7 @@ Via `pyproject.toml`:
|
|
|
89
89
|
|
|
90
90
|
```toml
|
|
91
91
|
dependencies = [
|
|
92
|
-
"tempest-fastapi-sdk>=0.
|
|
92
|
+
"tempest-fastapi-sdk>=0.37.0",
|
|
93
93
|
]
|
|
94
94
|
```
|
|
95
95
|
|
|
@@ -114,13 +114,18 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
114
114
|
| `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
|
|
115
115
|
| `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
|
|
116
116
|
| `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
|
|
117
|
+
| `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
|
|
118
|
+
| `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
|
|
117
119
|
| `[all]` | everything above | every helper |
|
|
118
120
|
|
|
119
121
|
```bash
|
|
120
122
|
pip install "tempest-fastapi-sdk[auth,upload]" # only what the service uses
|
|
121
|
-
pip install "tempest-fastapi-sdk[
|
|
123
|
+
pip install "tempest-fastapi-sdk[postgres]" # add the async DB driver you deploy with
|
|
124
|
+
pip install "tempest-fastapi-sdk[all]" # or pull everything
|
|
122
125
|
```
|
|
123
126
|
|
|
127
|
+
> **The SDK ships no database driver by default.** `sqlalchemy[asyncio]` is core, but the async DBAPI is your deploy choice — add `[sqlite]` (`aiosqlite`, dev default) or `[postgres]` (`asyncpg`, production). Without one, the engine raises `ModuleNotFoundError` for the driver on first connection. Services scaffolded with `tempest new` already pin `aiosqlite` and carry a commented `asyncpg` line in `pyproject.toml`.
|
|
128
|
+
|
|
124
129
|
Since `0.7.1` every optional dependency is imported lazily at first instantiation, so `import tempest_fastapi_sdk` works with any subset of extras — instantiating a helper whose extra is missing raises `ImportError` with a clear hint pointing at the right one.
|
|
125
130
|
|
|
126
131
|
---
|
|
@@ -3318,7 +3323,7 @@ tempest user list --admin # admins only
|
|
|
3318
3323
|
|
|
3319
3324
|
### Admin site recipe
|
|
3320
3325
|
|
|
3321
|
-
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks.
|
|
3326
|
+
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks. The panel is feature-complete (Django-admin parity): a list view with search / per-field filters / sortable columns, full CRUD (create / edit / delete), bulk actions, CSV/JSON export, FK-select widgets, a dashboard with live row counts + system metrics, optional TOTP MFA at login, and an audit trail stamping `created_by` / `updated_by`. Still on the roadmap: file upload and inline/related editing.
|
|
3322
3327
|
|
|
3323
3328
|
Requires the `[admin]` extra:
|
|
3324
3329
|
|
|
@@ -3437,11 +3442,19 @@ app.include_router(
|
|
|
3437
3442
|
`make_admin_router` mounts:
|
|
3438
3443
|
|
|
3439
3444
|
- `GET /admin/login`, `POST /admin/login`, `POST /admin/logout` — auth flow.
|
|
3440
|
-
- `GET
|
|
3441
|
-
- `GET /admin
|
|
3442
|
-
- `GET /admin/m/{slug}
|
|
3445
|
+
- `GET/POST /admin/mfa` — TOTP challenge (second factor) between password and access, for principals with MFA enabled.
|
|
3446
|
+
- `GET /admin/` — dashboard: a card per model with **row count** + Browse/New, plus a **metrics panel** (CPU/RAM/disk via `MetricsUtils`; on by default, omitted without the `[metrics]` extra, disabled with `make_admin_router(show_metrics=False)`).
|
|
3447
|
+
- `GET /admin/m/{slug}/` — list view with pagination + free-text search (`?q=`) + per-field filters (`?filter_<field>=value`) + clickable **column sorting** (`?sort=<column>&dir=asc|desc`).
|
|
3448
|
+
- `GET /admin/m/{slug}/export.csv` / `export.json` — **export** the current result set (honoring search/filters/sort) as CSV or JSON (row cap via `make_admin_router(export_max_rows=…)`, default 5000).
|
|
3449
|
+
- `POST /admin/m/{slug}/bulk` — **bulk actions** (delete / activate / deactivate) on selected rows.
|
|
3450
|
+
- `GET/POST /admin/m/{slug}/new` — **create** a record (when `can_create`).
|
|
3451
|
+
- `GET /admin/m/{slug}/{identity}` — detail view with Edit/Delete buttons + an Audit panel.
|
|
3452
|
+
- `GET/POST /admin/m/{slug}/{identity}/edit` — **edit** a record (when `can_edit`).
|
|
3453
|
+
- `POST /admin/m/{slug}/{identity}/delete` — **delete** a record (when `can_delete`).
|
|
3443
3454
|
- `GET /admin/static/{path}` — bundled CSS/HTMX assets.
|
|
3444
3455
|
|
|
3456
|
+
Write operations (create/edit/delete/bulk) are gated by the `AdminModel` flags `can_create` / `can_edit` / `can_delete` (all `True` by default; a disabled view returns `404`), carry a per-session CSRF token validated server-side, derive form widgets from the column type, render an FK-select dropdown for foreign keys whose target has a registered `AdminModel`, and stamp `created_by` / `updated_by` (from `AuditMixin`) with the acting admin's id.
|
|
3457
|
+
|
|
3445
3458
|
#### 4. Session security defaults
|
|
3446
3459
|
|
|
3447
3460
|
`SignedCookieSessionStore` uses `itsdangerous.TimestampSigner` (HMAC-SHA256) to sign a single cookie:
|
|
@@ -3450,7 +3463,7 @@ app.include_router(
|
|
|
3450
3463
|
- `Secure` flagged when `cookie_secure=True` (default; flip off in local HTTP dev).
|
|
3451
3464
|
- `SameSite=Lax` (`"lax"`/`"strict"`/`"none"` accepted).
|
|
3452
3465
|
- Default lifetime `8h`; expired or tampered cookies are rejected silently.
|
|
3453
|
-
- Per-session CSRF token is generated at login and required by every form POST (
|
|
3466
|
+
- Per-session CSRF token is generated at login and required by every form POST (login, logout, create, edit, delete, bulk actions).
|
|
3454
3467
|
- `secret_key` must be at least 32 bytes — short keys raise `ValueError` at construction time.
|
|
3455
3468
|
|
|
3456
3469
|
#### 5. Plug in a custom auth backend
|
|
@@ -29,6 +29,9 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
29
29
|
| `[minio]` | `minio` | `AsyncMinIOClient`, `MinIOUploadStorage` |
|
|
30
30
|
| `[http]` | `httpx` | `HTTPClient` + `RetryPolicy` + circuit-breaker |
|
|
31
31
|
| `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
|
|
32
|
+
| `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA (TOTP) endpoints on the bundled auth flow |
|
|
33
|
+
| `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
|
|
34
|
+
| `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
|
|
32
35
|
| `[all]` | everything above | every helper |
|
|
33
36
|
|
|
34
37
|
=== "Subset (recommended)"
|
|
@@ -46,17 +49,25 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
46
49
|
=== "uv add"
|
|
47
50
|
|
|
48
51
|
```bash
|
|
49
|
-
uv add "tempest-fastapi-sdk[auth,upload]>=0.
|
|
52
|
+
uv add "tempest-fastapi-sdk[auth,upload,postgres]>=0.37.0"
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
=== "pyproject.toml"
|
|
53
56
|
|
|
54
57
|
```toml
|
|
55
58
|
dependencies = [
|
|
56
|
-
"tempest-fastapi-sdk[auth,upload]>=0.
|
|
59
|
+
"tempest-fastapi-sdk[auth,upload,postgres]>=0.37.0",
|
|
57
60
|
]
|
|
58
61
|
```
|
|
59
62
|
|
|
63
|
+
!!! warning "The SDK ships no database driver by default"
|
|
64
|
+
`sqlalchemy[asyncio]` is core, but the async DBAPI is your deploy
|
|
65
|
+
choice: install `[sqlite]` (`aiosqlite`, dev default) or `[postgres]`
|
|
66
|
+
(`asyncpg`, production). Without one, the engine raises
|
|
67
|
+
`ModuleNotFoundError` for the driver on first connection. Services
|
|
68
|
+
scaffolded with `tempest new` already pin `aiosqlite` and carry a
|
|
69
|
+
commented `asyncpg` line in `pyproject.toml`.
|
|
70
|
+
|
|
60
71
|
!!! info "Lazy imports"
|
|
61
72
|
Since 0.7.1 every optional dependency is imported lazily at first instantiation, so `import tempest_fastapi_sdk` works even when only a subset of extras is installed. Instantiating a helper whose extra is missing raises `ImportError` with a clear hint pointing at the right extra.
|
|
62
73
|
|
|
@@ -29,6 +29,9 @@ Os helpers mais ricos puxam dependências de terceiros que só são necessárias
|
|
|
29
29
|
| `[minio]` | `minio` | `AsyncMinIOClient`, `MinIOUploadStorage` |
|
|
30
30
|
| `[http]` | `httpx` | `HTTPClient` + `RetryPolicy` + circuit-breaker |
|
|
31
31
|
| `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
|
|
32
|
+
| `[mfa]` | `pyotp` | `TOTPHelper` + endpoints MFA/2FA (TOTP) do fluxo bundled de auth |
|
|
33
|
+
| `[sqlite]` | `aiosqlite` | driver async SQLite para URLs `sqlite+aiosqlite://` (default de dev) |
|
|
34
|
+
| `[postgres]` | `asyncpg` | driver async PostgreSQL para URLs `postgresql+asyncpg://` (produção) |
|
|
32
35
|
| `[all]` | tudo acima | todos os helpers |
|
|
33
36
|
|
|
34
37
|
=== "Subconjunto (recomendado)"
|
|
@@ -46,17 +49,25 @@ Os helpers mais ricos puxam dependências de terceiros que só são necessárias
|
|
|
46
49
|
=== "uv add"
|
|
47
50
|
|
|
48
51
|
```bash
|
|
49
|
-
uv add "tempest-fastapi-sdk[auth,upload]>=0.
|
|
52
|
+
uv add "tempest-fastapi-sdk[auth,upload,postgres]>=0.37.0"
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
=== "pyproject.toml"
|
|
53
56
|
|
|
54
57
|
```toml
|
|
55
58
|
dependencies = [
|
|
56
|
-
"tempest-fastapi-sdk[auth,upload]>=0.
|
|
59
|
+
"tempest-fastapi-sdk[auth,upload,postgres]>=0.37.0",
|
|
57
60
|
]
|
|
58
61
|
```
|
|
59
62
|
|
|
63
|
+
!!! warning "O SDK não traz driver de banco por padrão"
|
|
64
|
+
`sqlalchemy[asyncio]` é dependência core, mas o DBAPI async é escolha
|
|
65
|
+
do seu deploy: instale `[sqlite]` (`aiosqlite`, default de dev) ou
|
|
66
|
+
`[postgres]` (`asyncpg`, produção). Sem nenhum, o engine levanta
|
|
67
|
+
`ModuleNotFoundError` do driver na primeira conexão. Serviços
|
|
68
|
+
criados com `tempest new` já pinam `aiosqlite` e carregam uma linha
|
|
69
|
+
`asyncpg` comentada no `pyproject.toml`.
|
|
70
|
+
|
|
60
71
|
!!! info "Imports preguiçosos"
|
|
61
72
|
Desde a 0.7.1 toda dependência opcional é importada de forma preguiçosa na primeira instanciação, então `import tempest_fastapi_sdk` funciona mesmo quando só um subconjunto de extras está instalado. Instanciar um helper cujo extra está faltando levanta `ImportError` com uma dica clara apontando para o extra certo.
|
|
62
73
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Admin site
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks.
|
|
4
|
+
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks. The panel is feature-complete (Django-admin parity): a list view with search / per-field filters / sortable columns, full CRUD (create / edit / delete), bulk actions, CSV/JSON export, FK-select widgets, a dashboard with live row counts + system metrics, optional TOTP MFA at login, and an audit trail stamping `created_by` / `updated_by`. Still on the roadmap: file upload and inline/related editing.
|
|
5
5
|
|
|
6
6
|
Requires the `[admin]` extra:
|
|
7
7
|
|
|
@@ -120,11 +120,33 @@ app.include_router(
|
|
|
120
120
|
`make_admin_router` mounts:
|
|
121
121
|
|
|
122
122
|
- `GET /admin/login`, `POST /admin/login`, `POST /admin/logout` — auth flow.
|
|
123
|
-
- `GET
|
|
124
|
-
- `GET /admin
|
|
125
|
-
- `GET /admin/m/{slug}
|
|
123
|
+
- `GET/POST /admin/mfa` — TOTP second-factor challenge between the password step and access, for MFA-enabled principals.
|
|
124
|
+
- `GET /admin/` — dashboard: a card per model with its **live row count** + Browse/New, plus a **metrics panel** (CPU/RAM/disk via `MetricsUtils`). On by default, omitted without the `[metrics]` extra, disable with `make_admin_router(show_metrics=False)`.
|
|
125
|
+
- `GET /admin/m/{slug}/` — list view with pagination + free-text search (`?q=`) + per-field filters (`?filter_<field>=value`) + clickable **column sorting** (`?sort=<column>&dir=asc|desc`).
|
|
126
|
+
- `GET /admin/m/{slug}/export.csv` / `export.json` — **export** the current result set (honoring search/filters/sort) as CSV or JSON. Row cap via `make_admin_router(export_max_rows=…)` (default 5000).
|
|
127
|
+
- `POST /admin/m/{slug}/bulk` — **bulk actions** (delete / activate / deactivate) on the selected rows.
|
|
128
|
+
- `GET/POST /admin/m/{slug}/new` — **create** a record (when `can_create`).
|
|
129
|
+
- `GET /admin/m/{slug}/{identity}` — detail view with Edit/Delete controls.
|
|
130
|
+
- `GET/POST /admin/m/{slug}/{identity}/edit` — **edit** a record (when `can_edit`).
|
|
131
|
+
- `POST /admin/m/{slug}/{identity}/delete` — **delete** a record (when `can_delete`).
|
|
126
132
|
- `GET /admin/static/{path}` — bundled CSS/HTMX assets.
|
|
127
133
|
|
|
134
|
+
!!! info "Write CRUD + permissions"
|
|
135
|
+
Create/edit/delete are gated by `AdminModel` flags: `can_create` / `can_edit` / `can_delete` (all `True` by default; a disabled view returns `404`). Every write POST carries the session CSRF token, verified server-side (`403` on mismatch). **Field widgets** are derived from the column type — text / textarea (long strings) / number / checkbox / `datetime-local` / date / `select` for enums — with required-field + per-field validation errors re-rendered on the form.
|
|
136
|
+
|
|
137
|
+
**Bulk actions**: the list view shows per-row checkboxes + select-all and an action bar (delete / activate / deactivate) operating on the checked rows via `POST .../bulk` (CSRF + `can_delete`/`can_edit` flags), backed by `BaseRepository.delete_batch` / `bulk_update`.
|
|
138
|
+
|
|
139
|
+
**FK-select**: a foreign-key column whose target has a registered `AdminModel` renders as a dropdown of the related rows (like Django's FK select) on the form, instead of a raw UUID input. The option label comes from the referenced admin's first `search_fields` entry (fallback: a `name`/`title`/`email` attribute, then the id). Capped at 1000 rows; FKs to unmanaged tables stay UUID inputs.
|
|
140
|
+
|
|
141
|
+
**MFA login**: a principal with MFA enabled (`MFAMixin`'s `totp_secret`/`totp_enabled_at`) goes through a TOTP challenge at `/admin/mfa` after the password — only a valid code grants access. Enable it via `UserModelAuthBackend(UserModel, mfa_issuer=...)`; custom backends override `mfa_enabled`/`verify_mfa`.
|
|
142
|
+
|
|
143
|
+
**Audit trail**: create/edit through the admin stamps `created_by`/`updated_by` (from `AuditMixin`) with the acting admin's id; the detail view shows an **Audit** panel with timestamps and — when the model has the audit columns — the actor (UUID resolved to a display name via the auth backend). Models without `AuditMixin` show timestamps only.
|
|
144
|
+
|
|
145
|
+
Not yet included (later roadmap phases): file upload, inline/related editing.
|
|
146
|
+
|
|
147
|
+
!!! tip "Responsive by default"
|
|
148
|
+
The bundled templates + CSS are responsive: on narrow screens (≤600px) the header stacks, search/filters/actions go full-width, tables get horizontal scroll (never breaking the layout), and the detail grid collapses to a single column. Column headers are clickable to toggle sort order (▲/▼).
|
|
149
|
+
|
|
128
150
|
#### 4. Session security defaults
|
|
129
151
|
|
|
130
152
|
`SignedCookieSessionStore` uses `itsdangerous.TimestampSigner` (HMAC-SHA256) to sign a single cookie:
|
|
@@ -133,7 +155,7 @@ app.include_router(
|
|
|
133
155
|
- `Secure` flagged when `cookie_secure=True` (default; flip off in local HTTP dev).
|
|
134
156
|
- `SameSite=Lax` (`"lax"`/`"strict"`/`"none"` accepted).
|
|
135
157
|
- Default lifetime `8h`; expired or tampered cookies are rejected silently.
|
|
136
|
-
- Per-session CSRF token is generated at login and required by every form POST (
|
|
158
|
+
- Per-session CSRF token is generated at login and required by every form POST (login, logout, create, edit, delete, bulk actions).
|
|
137
159
|
- `secret_key` must be at least 32 bytes — short keys raise `ValueError` at construction time.
|
|
138
160
|
|
|
139
161
|
#### 5. Plug in a custom auth backend
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Painel admin
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
UI de gerenciamento no estilo Django montada sob `/admin`. Operadores entram com uma linha de usuário do banco (sem store de senha de admin separado) e navegam por todo modelo registrado pelo navegador, então a porta do banco pode ficar fechada em redes privadas.
|
|
4
|
+
UI de gerenciamento no estilo Django montada sob `/admin`. Operadores entram com uma linha de usuário do banco (sem store de senha de admin separado) e navegam por todo modelo registrado pelo navegador, então a porta do banco pode ficar fechada em redes privadas. O painel é completo (paridade com o Django admin): list view com busca / filtros por campo / colunas ordenáveis, CRUD completo (criar / editar / excluir), ações em massa, export CSV/JSON, widgets FK-select, dashboard com contagens de linhas + métricas de sistema, MFA TOTP opcional no login, e trilha de auditoria carimbando `created_by` / `updated_by`. Ainda no roadmap: upload de arquivo e edição inline/relacionada.
|
|
5
5
|
|
|
6
6
|
Requer o extra `[admin]`:
|
|
7
7
|
|
|
@@ -120,11 +120,33 @@ app.include_router(
|
|
|
120
120
|
`make_admin_router` monta:
|
|
121
121
|
|
|
122
122
|
- `GET /admin/login`, `POST /admin/login`, `POST /admin/logout` — fluxo de auth.
|
|
123
|
-
- `GET
|
|
124
|
-
- `GET /admin
|
|
125
|
-
- `GET /admin/m/{slug}
|
|
123
|
+
- `GET/POST /admin/mfa` — desafio TOTP (segundo fator) entre a senha e o acesso, para principais com MFA habilitado.
|
|
124
|
+
- `GET /admin/` — dashboard: card por modelo com **contagem de linhas** + Browse/New, e um **painel de métricas** (CPU/RAM/disco via `MetricsUtils`). Painel ligado por default, omitido sem o extra `[metrics]`, desligável com `make_admin_router(show_metrics=False)`.
|
|
125
|
+
- `GET /admin/m/{slug}/` — list view com paginação + busca em texto livre (`?q=`) + filtros por campo (`?filter_<field>=value`) + **ordenação por coluna** clicável (`?sort=<coluna>&dir=asc|desc`).
|
|
126
|
+
- `GET /admin/m/{slug}/export.csv` / `export.json` — **exporta** o resultado atual (respeitando busca/filtros/ordenação) como CSV ou JSON. Limite de linhas via `make_admin_router(export_max_rows=…)` (default 5000).
|
|
127
|
+
- `POST /admin/m/{slug}/bulk` — **ações em massa** (delete / activate / deactivate) nas linhas selecionadas.
|
|
128
|
+
- `GET/POST /admin/m/{slug}/new` — **criar** registro (quando `can_create`).
|
|
129
|
+
- `GET /admin/m/{slug}/{identity}` — detail view com botões Edit/Delete.
|
|
130
|
+
- `GET/POST /admin/m/{slug}/{identity}/edit` — **editar** registro (quando `can_edit`).
|
|
131
|
+
- `POST /admin/m/{slug}/{identity}/delete` — **excluir** registro (quando `can_delete`).
|
|
126
132
|
- `GET /admin/static/{path}` — assets CSS/HTMX embutidos.
|
|
127
133
|
|
|
134
|
+
!!! info "Escrita (CRUD) + permissões"
|
|
135
|
+
Create/edit/delete são controlados por flags no `AdminModel`: `can_create` / `can_edit` / `can_delete` (todas `True` por default; uma view desativada responde `404`). Todo POST de escrita carrega o token CSRF da sessão, validado no servidor (`403` em mismatch). Os **widgets de campo** são derivados do tipo da coluna — texto / textarea (strings longas) / number / checkbox / `datetime-local` / date / `select` para enums — com validação de obrigatórios + erros por campo re-renderizados no formulário.
|
|
136
|
+
|
|
137
|
+
**Ações em massa**: a list view mostra checkboxes por linha + select-all e uma barra de ação (delete / activate / deactivate) que opera nas linhas marcadas via `POST .../bulk` (CSRF + flags `can_delete`/`can_edit`), apoiada em `BaseRepository.delete_batch` / `bulk_update`.
|
|
138
|
+
|
|
139
|
+
**FK-select**: uma coluna FK cujo destino tem `AdminModel` registrado vira um dropdown das linhas relacionadas (igual ao FK select do Django) no formulário, em vez de um input UUID cru. O label da opção vem do primeiro `search_fields` do admin referenciado (fallback: atributo `name`/`title`/`email`, depois o id). Limitado a 1000 linhas; FK para tabela não-gerenciada continua input UUID.
|
|
140
|
+
|
|
141
|
+
**MFA no login**: um principal com MFA habilitado (colunas `totp_secret`/`totp_enabled_at` do `MFAMixin`) passa por um desafio TOTP em `/admin/mfa` depois da senha — só um código válido libera o acesso. Habilite passando um usuário com MFA via `UserModelAuthBackend(UserModel, mfa_issuer=...)`; backends customizados sobrescrevem `mfa_enabled`/`verify_mfa`.
|
|
142
|
+
|
|
143
|
+
**Audit trail**: create/edit pelo admin carimba `created_by`/`updated_by` (do `AuditMixin`) com o id do admin atuante; o detail mostra um painel **Audit** com timestamps e — quando o modelo tem as colunas de auditoria — o ator (UUID resolvido para nome via o auth backend). Modelos sem `AuditMixin` mostram só os timestamps.
|
|
144
|
+
|
|
145
|
+
Ainda **não** incluídos (fases futuras do roadmap): upload de arquivo, inline/related editing.
|
|
146
|
+
|
|
147
|
+
!!! tip "Responsivo por padrão"
|
|
148
|
+
Os templates + CSS embutidos são responsivos: em telas estreitas (≤600px) o header empilha, busca/filtros/ações viram full-width, as tabelas ganham scroll horizontal (nunca quebram o layout) e o grid do detail colapsa para uma coluna. Headers de coluna são clicáveis para alternar a ordenação (▲/▼).
|
|
149
|
+
|
|
128
150
|
#### 4. Defaults de segurança de sessão
|
|
129
151
|
|
|
130
152
|
`SignedCookieSessionStore` usa `itsdangerous.TimestampSigner` (HMAC-SHA256) para assinar um único cookie:
|
|
@@ -133,7 +155,7 @@ app.include_router(
|
|
|
133
155
|
- `Secure` marcado quando `cookie_secure=True` (padrão; desligue no dev HTTP local).
|
|
134
156
|
- `SameSite=Lax` (`"lax"`/`"strict"`/`"none"` aceitos).
|
|
135
157
|
- Tempo de vida padrão `8h`; cookies expirados ou adulterados são rejeitados silenciosamente.
|
|
136
|
-
- Um token CSRF por sessão é gerado no login e exigido por todo POST de formulário (
|
|
158
|
+
- Um token CSRF por sessão é gerado no login e exigido por todo POST de formulário (login, logout, criar, editar, excluir, ações em massa).
|
|
137
159
|
- `secret_key` deve ter ao menos 32 bytes — chaves curtas levantam `ValueError` no momento da construção.
|
|
138
160
|
|
|
139
161
|
#### 5. Plugue um backend de auth customizado
|
|
@@ -56,9 +56,9 @@ Since v0.25.0 the scaffold generates a `docker-compose.yaml` carrying **only** t
|
|
|
56
56
|
|
|
57
57
|
| Extra | Container | Exposed port(s) |
|
|
58
58
|
|-------|-----------|-----------------|
|
|
59
|
-
| (always) | `postgres:
|
|
60
|
-
| `[cache]` | `redis:
|
|
61
|
-
| `[queue]` / `[tasks]` | `rabbitmq:
|
|
59
|
+
| (always) | `postgres:18-alpine` | 5432 |
|
|
60
|
+
| `[cache]` | `redis:8-alpine` | 6379 |
|
|
61
|
+
| `[queue]` / `[tasks]` | `rabbitmq:4-management-alpine` | 5672 (AMQP) + 15672 (UI) |
|
|
62
62
|
| `[minio]` | `minio/minio` + bootstrap mc | 9000 (API) + 9001 (Console) |
|
|
63
63
|
| `[email]` | `mailhog/mailhog` | 1025 (SMTP) + 8025 (UI) |
|
|
64
64
|
|
|
@@ -73,6 +73,18 @@ Generates:
|
|
|
73
73
|
- `postgres`, `redis`, `minio` (+ `minio-bootstrap` creating the `uploads` bucket), `mailhog`
|
|
74
74
|
- `.env.example` with `REDIS_URL`, `MINIO_*`, `EMAIL_HOST=localhost`, `EMAIL_PORT=1025`
|
|
75
75
|
|
|
76
|
+
!!! info "Credentials come from `.env`, not hardcoded in the compose"
|
|
77
|
+
As of v0.37.0, no credential is written straight into
|
|
78
|
+
`docker-compose.yaml`. Each `environment:` block uses the
|
|
79
|
+
`${VAR:-default}` form, and Docker Compose resolves `VAR` from the
|
|
80
|
+
`.env` next to the compose file. The `:-default` keeps the stack
|
|
81
|
+
bootable before you copy `.env.example` to `.env` — but set real
|
|
82
|
+
secrets in `.env` for any non-throwaway deploy. Variables read by
|
|
83
|
+
compose: `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_DB`,
|
|
84
|
+
`RABBITMQ_DEFAULT_USER` / `RABBITMQ_DEFAULT_PASS` /
|
|
85
|
+
`RABBITMQ_DEFAULT_VHOST`, `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD`
|
|
86
|
+
— all with their defaults already in `.env.example`.
|
|
87
|
+
|
|
76
88
|
Boot it all:
|
|
77
89
|
|
|
78
90
|
```bash
|
|
@@ -56,9 +56,9 @@ Desde a v0.25.0 o scaffold gera um `docker-compose.yaml` com **apenas** os servi
|
|
|
56
56
|
|
|
57
57
|
| Extra | Container subido | Porta(s) exposta(s) |
|
|
58
58
|
|-------|------------------|---------------------|
|
|
59
|
-
| (sempre) | `postgres:
|
|
60
|
-
| `[cache]` | `redis:
|
|
61
|
-
| `[queue]` / `[tasks]` | `rabbitmq:
|
|
59
|
+
| (sempre) | `postgres:18-alpine` | 5432 |
|
|
60
|
+
| `[cache]` | `redis:8-alpine` | 6379 |
|
|
61
|
+
| `[queue]` / `[tasks]` | `rabbitmq:4-management-alpine` | 5672 (AMQP) + 15672 (UI) |
|
|
62
62
|
| `[minio]` | `minio/minio` + bootstrap mc | 9000 (API) + 9001 (Console) |
|
|
63
63
|
| `[email]` | `mailhog/mailhog` | 1025 (SMTP) + 8025 (UI) |
|
|
64
64
|
|
|
@@ -73,6 +73,18 @@ Gera:
|
|
|
73
73
|
- `postgres`, `redis`, `minio` (+ `minio-bootstrap` que cria o bucket `uploads`), `mailhog`
|
|
74
74
|
- `.env.example` com `REDIS_URL`, `MINIO_*`, `EMAIL_HOST=localhost`, `EMAIL_PORT=1025`
|
|
75
75
|
|
|
76
|
+
!!! info "Credenciais vêm do `.env`, não estão hardcoded no compose"
|
|
77
|
+
A partir da v0.37.0, nenhuma credencial é gravada direto no
|
|
78
|
+
`docker-compose.yaml`. Cada bloco `environment:` usa a forma
|
|
79
|
+
`${VAR:-default}`, e o Docker Compose resolve `VAR` a partir do
|
|
80
|
+
`.env` ao lado do compose. O `:-default` mantém o stack subindo
|
|
81
|
+
antes de você copiar `.env.example` para `.env` — mas defina
|
|
82
|
+
segredos reais no `.env` para qualquer deploy não-descartável.
|
|
83
|
+
Variáveis lidas pelo compose: `POSTGRES_USER` / `POSTGRES_PASSWORD`
|
|
84
|
+
/ `POSTGRES_DB`, `RABBITMQ_DEFAULT_USER` / `RABBITMQ_DEFAULT_PASS`
|
|
85
|
+
/ `RABBITMQ_DEFAULT_VHOST`, `MINIO_ROOT_USER` /
|
|
86
|
+
`MINIO_ROOT_PASSWORD` — todas com seus padrões já no `.env.example`.
|
|
87
|
+
|
|
76
88
|
Subir tudo:
|
|
77
89
|
|
|
78
90
|
```bash
|
|
@@ -151,4 +151,4 @@ url = await storage.presigned_url("logo.png", expires=timedelta(hours=1))
|
|
|
151
151
|
|
|
152
152
|
## When to use presigned PUT directly
|
|
153
153
|
|
|
154
|
-
For files > 50 MB, skip the in-memory buffer — have the client `PUT` straight to MinIO via a presigned URL. See [Storage MinIO/S3](storage.md#presigned-url
|
|
154
|
+
For files > 50 MB, skip the in-memory buffer — have the client `PUT` straight to MinIO via a presigned URL. See [Storage MinIO/S3](storage.md#presigned-url-direct-browser-upload).
|
|
@@ -26,9 +26,14 @@ Gerada automaticamente a partir das docstrings do SDK via [`mkdocstrings`](https
|
|
|
26
26
|
|
|
27
27
|
::: tempest_fastapi_sdk.db.model.BaseModel
|
|
28
28
|
::: tempest_fastapi_sdk.db.user_model.BaseUserModel
|
|
29
|
+
::: tempest_fastapi_sdk.db.user_token_model.BaseUserTokenModel
|
|
30
|
+
::: tempest_fastapi_sdk.db.user_token_model.make_user_token_model
|
|
31
|
+
::: tempest_fastapi_sdk.db.user_recovery_code_model.BaseUserRecoveryCodeModel
|
|
32
|
+
::: tempest_fastapi_sdk.db.user_recovery_code_model.make_user_recovery_code_model
|
|
29
33
|
::: tempest_fastapi_sdk.db.repository.BaseRepository
|
|
30
34
|
::: tempest_fastapi_sdk.db.mixins.SoftDeleteMixin
|
|
31
35
|
::: tempest_fastapi_sdk.db.mixins.AuditMixin
|
|
36
|
+
::: tempest_fastapi_sdk.db.mixins.MFAMixin
|
|
32
37
|
::: tempest_fastapi_sdk.db.connection.AsyncDatabaseManager
|
|
33
38
|
::: tempest_fastapi_sdk.db.migrations.AlembicHelper
|
|
34
39
|
|
|
@@ -120,6 +125,10 @@ Gerada automaticamente a partir das docstrings do SDK via [`mkdocstrings`](https
|
|
|
120
125
|
::: tempest_fastapi_sdk.auth.schemas.PasswordResetConfirmSchema
|
|
121
126
|
::: tempest_fastapi_sdk.auth.schemas.ActivationToken
|
|
122
127
|
::: tempest_fastapi_sdk.auth.schemas.PasswordResetToken
|
|
128
|
+
::: tempest_fastapi_sdk.auth.schemas.MFAEnrollResponseSchema
|
|
129
|
+
::: tempest_fastapi_sdk.auth.schemas.MFAConfirmSchema
|
|
130
|
+
::: tempest_fastapi_sdk.auth.schemas.MFAVerifySchema
|
|
131
|
+
::: tempest_fastapi_sdk.auth.schemas.MFADisableSchema
|
|
123
132
|
|
|
124
133
|
### `tempest_fastapi_sdk.sessions`
|
|
125
134
|
|
|
@@ -211,6 +220,7 @@ Gerada automaticamente a partir das docstrings do SDK via [`mkdocstrings`](https
|
|
|
211
220
|
|
|
212
221
|
::: tempest_fastapi_sdk.utils.password.PasswordUtils
|
|
213
222
|
::: tempest_fastapi_sdk.utils.jwt.JWTUtils
|
|
223
|
+
::: tempest_fastapi_sdk.utils.totp.TOTPHelper
|
|
214
224
|
::: tempest_fastapi_sdk.utils.email.EmailUtils
|
|
215
225
|
::: tempest_fastapi_sdk.utils.upload.UploadUtils
|
|
216
226
|
::: tempest_fastapi_sdk.utils.metrics.MetricsUtils
|