fastapi-fullstack 0.1.7__py3-none-any.whl
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.
- fastapi_fullstack-0.1.7.dist-info/METADATA +739 -0
- fastapi_fullstack-0.1.7.dist-info/RECORD +241 -0
- fastapi_fullstack-0.1.7.dist-info/WHEEL +4 -0
- fastapi_fullstack-0.1.7.dist-info/entry_points.txt +2 -0
- fastapi_fullstack-0.1.7.dist-info/licenses/LICENSE +21 -0
- fastapi_gen/__init__.py +3 -0
- fastapi_gen/cli.py +442 -0
- fastapi_gen/config.py +356 -0
- fastapi_gen/generator.py +207 -0
- fastapi_gen/prompts.py +874 -0
- fastapi_gen/template/VARIABLES.md +276 -0
- fastapi_gen/template/cookiecutter.json +93 -0
- fastapi_gen/template/hooks/post_gen_project.py +355 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/.env.prod.example +56 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +150 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/.gitignore +109 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/AGENTS.md +55 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/CLAUDE.md +99 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/Makefile +315 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/README.md +768 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.dockerignore +60 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.env.example +155 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.pre-commit-config.yaml +32 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/Dockerfile +56 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/env.py +76 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/script.py.mako +30 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/.gitkeep +0 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic.ini +48 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/__init__.py +3 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/admin.py +447 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py +23 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/assistant.py +226 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/langchain_assistant.py +226 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/prompts.py +10 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/__init__.py +13 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/datetime_tool.py +17 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/__init__.py +1 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py +541 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/exception_handlers.py +98 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/router.py +10 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/__init__.py +9 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/__init__.py +87 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py +902 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py +395 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/conversations.py +498 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/health.py +227 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/items.py +275 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py +205 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/sessions.py +168 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/users.py +333 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/webhooks.py +477 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/ws.py +46 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py +221 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/clients/__init__.py +14 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/clients/redis.py +88 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/__init__.py +117 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/cleanup.py +75 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/example.py +28 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/commands/seed.py +266 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/__init__.py +5 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/cache.py +23 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/config.py +267 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py +153 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/exceptions.py +122 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/logfire_setup.py +101 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/middleware.py +99 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/oauth.py +23 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py +58 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/sanitize.py +271 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/security.py +102 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py +7 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/base.py +41 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/__init__.py +31 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/conversation.py +319 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/item.py +96 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/session.py +126 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +218 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py +244 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/session.py +130 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/main.py +334 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/pipelines/__init__.py +9 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/pipelines/base.py +73 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/__init__.py +49 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/base.py +154 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/conversation.py +838 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/item.py +222 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/session.py +318 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/user.py +322 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/webhook.py +358 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/__init__.py +50 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/base.py +57 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/conversation.py +192 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/item.py +52 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/session.py +42 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/token.py +31 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/user.py +64 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py +89 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/__init__.py +38 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/conversation.py +850 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/item.py +246 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/session.py +333 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/user.py +432 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py +561 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py +5 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/celery_app.py +64 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/taskiq_app.py +38 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/__init__.py +25 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/examples.py +106 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/schedules.py +29 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/tasks/taskiq_examples.py +92 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/__init__.py +1 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/commands.py +438 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +180 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/scripts/.gitkeep +0 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/__init__.py +1 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/__init__.py +1 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py +242 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py +151 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_health.py +113 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_items.py +310 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_users.py +253 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py +151 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_admin.py +890 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py +261 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_clients.py +183 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_commands.py +173 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py +143 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_pipelines.py +118 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories.py +181 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py +124 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py +363 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_worker.py +85 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.dev.yml +242 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.frontend.yml +31 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.prod.yml +435 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docker-compose.yml +241 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docs/adding_features.md +132 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docs/architecture.md +63 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docs/patterns.md +161 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/docs/testing.md +120 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.dockerignore +40 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.env.example +12 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.gitignore +45 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.prettierignore +19 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/.prettierrc +11 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/Dockerfile +44 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/README.md +648 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.setup.ts +49 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/auth.spec.ts +134 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/chat.spec.ts +207 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/e2e/home.spec.ts +73 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/instrumentation.ts +14 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/messages/en.json +84 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/messages/pl.json +84 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/next.config.ts +76 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/package.json +69 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/playwright.config.ts +101 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/postcss.config.mjs +7 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/layout.tsx +11 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/login/page.tsx +5 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(auth)/register/page.tsx +5 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/chat/page.tsx +48 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/dashboard/page.tsx +99 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/layout.tsx +17 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/(dashboard)/profile/page.tsx +152 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/auth/callback/page.tsx +113 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/layout.tsx +46 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/[locale]/page.tsx +73 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/login/route.ts +58 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/logout/route.ts +24 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/me/route.ts +39 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/oauth-callback/route.ts +50 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/refresh/route.ts +54 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/auth/register/route.ts +26 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/messages/route.ts +41 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/[id]/route.ts +108 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/conversations/route.ts +73 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/api/health/route.ts +21 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/globals.css +323 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/layout.tsx +22 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/app/providers.tsx +29 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/index.ts +2 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/login-form.tsx +120 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/auth/register-form.tsx +153 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-container.tsx +234 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/chat-input.tsx +72 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/conversation-sidebar.tsx +328 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/copy-button.tsx +46 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/index.ts +11 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/local-conversation-sidebar.tsx +295 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/markdown-content.tsx +167 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-item.tsx +79 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/message-list.tsx +18 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/chat/tool-call-card.tsx +79 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/google-icon.tsx +32 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/icons/index.ts +3 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/language-switcher.tsx +97 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/header.tsx +65 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/index.ts +2 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/layout/sidebar.tsx +82 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/index.ts +7 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-provider.tsx +53 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/theme/theme-toggle.tsx +105 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/badge.tsx +35 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.test.tsx +75 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/button.tsx +56 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/card.tsx +82 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/index.ts +13 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/input.tsx +21 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/label.tsx +21 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/components/ui/sheet.tsx +109 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/index.ts +7 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-auth.ts +97 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-chat.ts +203 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-conversations.ts +181 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-local-chat.ts +165 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/hooks/use-websocket.ts +105 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/i18n.ts +37 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/api-client.ts +90 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/constants.ts +39 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/server-api.ts +78 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.test.ts +44 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/lib/utils.ts +44 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/middleware.ts +31 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.test.ts +72 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/auth-store.ts +64 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-sidebar-store.ts +17 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/chat-store.ts +65 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/conversation-store.ts +76 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/index.ts +9 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/local-chat-store.ts +255 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/sidebar-store.ts +17 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/stores/theme-store.ts +44 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/api.ts +27 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/auth.ts +52 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/chat.ts +83 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/conversation.ts +49 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/src/types/index.ts +10 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/tsconfig.json +28 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/vitest.config.ts +36 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/frontend/vitest.setup.ts +56 -0
fastapi_gen/config.py
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"""Configuration models for project generation."""
|
|
2
|
+
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from importlib.metadata import version
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, EmailStr, Field, computed_field, model_validator
|
|
9
|
+
|
|
10
|
+
GENERATOR_NAME = "fastapi-fullstack"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_generator_version() -> str:
|
|
14
|
+
"""Get the current generator version from package metadata."""
|
|
15
|
+
try:
|
|
16
|
+
return version(GENERATOR_NAME)
|
|
17
|
+
except Exception:
|
|
18
|
+
return "0.0.0"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DatabaseType(str, Enum):
|
|
22
|
+
"""Supported database types."""
|
|
23
|
+
|
|
24
|
+
POSTGRESQL = "postgresql"
|
|
25
|
+
MONGODB = "mongodb"
|
|
26
|
+
SQLITE = "sqlite"
|
|
27
|
+
NONE = "none"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class AuthType(str, Enum):
|
|
31
|
+
"""Supported authentication types."""
|
|
32
|
+
|
|
33
|
+
JWT = "jwt"
|
|
34
|
+
API_KEY = "api_key"
|
|
35
|
+
BOTH = "both"
|
|
36
|
+
NONE = "none"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class BackgroundTaskType(str, Enum):
|
|
40
|
+
"""Supported background task systems."""
|
|
41
|
+
|
|
42
|
+
NONE = "none"
|
|
43
|
+
CELERY = "celery"
|
|
44
|
+
TASKIQ = "taskiq"
|
|
45
|
+
ARQ = "arq"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CIType(str, Enum):
|
|
49
|
+
"""Supported CI/CD systems."""
|
|
50
|
+
|
|
51
|
+
GITHUB = "github"
|
|
52
|
+
GITLAB = "gitlab"
|
|
53
|
+
NONE = "none"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class FrontendType(str, Enum):
|
|
57
|
+
"""Supported frontend frameworks."""
|
|
58
|
+
|
|
59
|
+
NONE = "none"
|
|
60
|
+
NEXTJS = "nextjs"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class WebSocketAuthType(str, Enum):
|
|
64
|
+
"""WebSocket authentication types for AI Agent."""
|
|
65
|
+
|
|
66
|
+
NONE = "none"
|
|
67
|
+
JWT = "jwt"
|
|
68
|
+
API_KEY = "api_key"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AdminEnvironmentType(str, Enum):
|
|
72
|
+
"""Admin panel environment restriction types."""
|
|
73
|
+
|
|
74
|
+
ALL = "all" # Available in all environments
|
|
75
|
+
DEV_ONLY = "dev_only" # Only in development
|
|
76
|
+
DEV_STAGING = "dev_staging" # Development + Staging (recommended)
|
|
77
|
+
DISABLED = "disabled" # Disabled everywhere
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class OAuthProvider(str, Enum):
|
|
81
|
+
"""Supported OAuth2 providers."""
|
|
82
|
+
|
|
83
|
+
NONE = "none"
|
|
84
|
+
GOOGLE = "google"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class AIFrameworkType(str, Enum):
|
|
88
|
+
"""Supported AI agent frameworks."""
|
|
89
|
+
|
|
90
|
+
PYDANTIC_AI = "pydantic_ai"
|
|
91
|
+
LANGCHAIN = "langchain"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class LLMProviderType(str, Enum):
|
|
95
|
+
"""Supported LLM providers."""
|
|
96
|
+
|
|
97
|
+
OPENAI = "openai"
|
|
98
|
+
ANTHROPIC = "anthropic"
|
|
99
|
+
OPENROUTER = "openrouter"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class RateLimitStorageType(str, Enum):
|
|
103
|
+
"""Rate limiting storage backends."""
|
|
104
|
+
|
|
105
|
+
MEMORY = "memory"
|
|
106
|
+
REDIS = "redis"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class ReverseProxyType(str, Enum):
|
|
110
|
+
"""Reverse proxy configuration options."""
|
|
111
|
+
|
|
112
|
+
TRAEFIK_INCLUDED = "traefik_included" # Include Traefik service + labels
|
|
113
|
+
TRAEFIK_EXTERNAL = "traefik_external" # External Traefik, include labels only
|
|
114
|
+
NONE = "none" # No reverse proxy, expose ports directly
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class LogfireFeatures(BaseModel):
|
|
118
|
+
"""Logfire instrumentation features."""
|
|
119
|
+
|
|
120
|
+
fastapi: bool = True
|
|
121
|
+
database: bool = True
|
|
122
|
+
redis: bool = False
|
|
123
|
+
celery: bool = False
|
|
124
|
+
httpx: bool = False
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class ProjectConfig(BaseModel):
|
|
128
|
+
"""Full project configuration."""
|
|
129
|
+
|
|
130
|
+
# Basic info
|
|
131
|
+
project_name: str = Field(..., min_length=1, pattern=r"^[a-z][a-z0-9_]*$")
|
|
132
|
+
project_description: str = "A FastAPI project"
|
|
133
|
+
|
|
134
|
+
author_name: str = "Your Name"
|
|
135
|
+
author_email: EmailStr = "your@email.com"
|
|
136
|
+
|
|
137
|
+
# Database
|
|
138
|
+
database: DatabaseType = DatabaseType.POSTGRESQL
|
|
139
|
+
db_pool_size: int = 5
|
|
140
|
+
db_max_overflow: int = 10
|
|
141
|
+
db_pool_timeout: int = 30
|
|
142
|
+
|
|
143
|
+
# Authentication
|
|
144
|
+
auth: AuthType = AuthType.JWT
|
|
145
|
+
oauth_provider: OAuthProvider = OAuthProvider.NONE
|
|
146
|
+
enable_session_management: bool = False
|
|
147
|
+
|
|
148
|
+
# Observability
|
|
149
|
+
enable_logfire: bool = True
|
|
150
|
+
logfire_features: LogfireFeatures = Field(default_factory=LogfireFeatures)
|
|
151
|
+
|
|
152
|
+
# Background tasks
|
|
153
|
+
background_tasks: BackgroundTaskType = BackgroundTaskType.NONE
|
|
154
|
+
|
|
155
|
+
# Optional integrations
|
|
156
|
+
enable_redis: bool = False
|
|
157
|
+
enable_caching: bool = False
|
|
158
|
+
enable_rate_limiting: bool = False
|
|
159
|
+
rate_limit_requests: int = 100
|
|
160
|
+
rate_limit_period: int = 60
|
|
161
|
+
rate_limit_storage: RateLimitStorageType = RateLimitStorageType.MEMORY
|
|
162
|
+
enable_pagination: bool = True
|
|
163
|
+
enable_sentry: bool = False
|
|
164
|
+
enable_prometheus: bool = False
|
|
165
|
+
enable_admin_panel: bool = False
|
|
166
|
+
admin_environments: AdminEnvironmentType = AdminEnvironmentType.DEV_STAGING
|
|
167
|
+
admin_require_auth: bool = True
|
|
168
|
+
enable_websockets: bool = False
|
|
169
|
+
enable_file_storage: bool = False
|
|
170
|
+
enable_ai_agent: bool = False
|
|
171
|
+
ai_framework: AIFrameworkType = AIFrameworkType.PYDANTIC_AI
|
|
172
|
+
llm_provider: LLMProviderType = LLMProviderType.OPENAI
|
|
173
|
+
enable_conversation_persistence: bool = False
|
|
174
|
+
enable_webhooks: bool = False
|
|
175
|
+
websocket_auth: WebSocketAuthType = WebSocketAuthType.NONE
|
|
176
|
+
enable_cors: bool = True
|
|
177
|
+
enable_orjson: bool = True
|
|
178
|
+
|
|
179
|
+
# Frontend features
|
|
180
|
+
enable_i18n: bool = False
|
|
181
|
+
|
|
182
|
+
# Example CRUD
|
|
183
|
+
include_example_crud: bool = True
|
|
184
|
+
|
|
185
|
+
# Dev tools
|
|
186
|
+
enable_pytest: bool = True
|
|
187
|
+
enable_precommit: bool = True
|
|
188
|
+
enable_makefile: bool = True
|
|
189
|
+
enable_docker: bool = True
|
|
190
|
+
reverse_proxy: ReverseProxyType = ReverseProxyType.TRAEFIK_INCLUDED
|
|
191
|
+
ci_type: CIType = CIType.GITHUB
|
|
192
|
+
enable_kubernetes: bool = False
|
|
193
|
+
generate_env: bool = True
|
|
194
|
+
|
|
195
|
+
# Python version
|
|
196
|
+
python_version: str = "3.12"
|
|
197
|
+
|
|
198
|
+
# Frontend
|
|
199
|
+
frontend: FrontendType = FrontendType.NONE
|
|
200
|
+
frontend_port: int = 3000
|
|
201
|
+
|
|
202
|
+
# Backend
|
|
203
|
+
backend_port: int = 8000
|
|
204
|
+
|
|
205
|
+
@computed_field
|
|
206
|
+
@property
|
|
207
|
+
def project_slug(self) -> str:
|
|
208
|
+
"""Return project slug (underscores instead of hyphens)."""
|
|
209
|
+
return self.project_name.replace("-", "_")
|
|
210
|
+
|
|
211
|
+
@model_validator(mode="after")
|
|
212
|
+
def validate_option_combinations(self) -> "ProjectConfig":
|
|
213
|
+
"""Validate that option combinations are valid.
|
|
214
|
+
|
|
215
|
+
Raises ValueError for invalid combinations:
|
|
216
|
+
- Admin panel requires a database (PostgreSQL or SQLite)
|
|
217
|
+
- Admin panel (SQLAdmin) does not support MongoDB
|
|
218
|
+
- Caching requires Redis to be enabled
|
|
219
|
+
- Session management requires a database
|
|
220
|
+
- Conversation persistence requires a database
|
|
221
|
+
"""
|
|
222
|
+
if self.enable_admin_panel and self.database == DatabaseType.NONE:
|
|
223
|
+
raise ValueError("Admin panel requires a database")
|
|
224
|
+
if self.enable_admin_panel and self.database == DatabaseType.MONGODB:
|
|
225
|
+
raise ValueError("Admin panel (SQLAdmin) requires PostgreSQL or SQLite")
|
|
226
|
+
if self.enable_caching and not self.enable_redis:
|
|
227
|
+
raise ValueError("Caching requires Redis to be enabled")
|
|
228
|
+
if self.enable_session_management and self.database == DatabaseType.NONE:
|
|
229
|
+
raise ValueError("Session management requires a database")
|
|
230
|
+
if self.enable_conversation_persistence and self.database == DatabaseType.NONE:
|
|
231
|
+
raise ValueError("Conversation persistence requires a database")
|
|
232
|
+
if (
|
|
233
|
+
self.enable_ai_agent
|
|
234
|
+
and self.ai_framework == AIFrameworkType.LANGCHAIN
|
|
235
|
+
and self.llm_provider == LLMProviderType.OPENROUTER
|
|
236
|
+
):
|
|
237
|
+
raise ValueError("OpenRouter is not supported with LangChain")
|
|
238
|
+
if (
|
|
239
|
+
self.enable_rate_limiting
|
|
240
|
+
and self.rate_limit_storage == RateLimitStorageType.REDIS
|
|
241
|
+
and not self.enable_redis
|
|
242
|
+
):
|
|
243
|
+
raise ValueError("Rate limiting with Redis storage requires Redis to be enabled")
|
|
244
|
+
return self
|
|
245
|
+
|
|
246
|
+
def to_cookiecutter_context(self) -> dict[str, Any]:
|
|
247
|
+
"""Convert config to cookiecutter context."""
|
|
248
|
+
return {
|
|
249
|
+
# Generator metadata
|
|
250
|
+
"generator_name": GENERATOR_NAME,
|
|
251
|
+
"generator_version": get_generator_version(),
|
|
252
|
+
"generated_at": datetime.now(UTC).isoformat(),
|
|
253
|
+
# Project info
|
|
254
|
+
"project_name": self.project_name,
|
|
255
|
+
"project_slug": self.project_slug,
|
|
256
|
+
"project_description": self.project_description,
|
|
257
|
+
"author_name": self.author_name,
|
|
258
|
+
"author_email": self.author_email,
|
|
259
|
+
# Database
|
|
260
|
+
"database": self.database.value,
|
|
261
|
+
"use_postgresql": self.database == DatabaseType.POSTGRESQL,
|
|
262
|
+
"use_mongodb": self.database == DatabaseType.MONGODB,
|
|
263
|
+
"use_sqlite": self.database == DatabaseType.SQLITE,
|
|
264
|
+
"use_database": self.database != DatabaseType.NONE,
|
|
265
|
+
"db_pool_size": self.db_pool_size,
|
|
266
|
+
"db_max_overflow": self.db_max_overflow,
|
|
267
|
+
"db_pool_timeout": self.db_pool_timeout,
|
|
268
|
+
# Auth
|
|
269
|
+
"auth": self.auth.value,
|
|
270
|
+
"use_jwt": self.auth in (AuthType.JWT, AuthType.BOTH),
|
|
271
|
+
"use_api_key": self.auth in (AuthType.API_KEY, AuthType.BOTH),
|
|
272
|
+
"use_auth": self.auth != AuthType.NONE,
|
|
273
|
+
# OAuth
|
|
274
|
+
"oauth_provider": self.oauth_provider.value,
|
|
275
|
+
"enable_oauth": self.oauth_provider != OAuthProvider.NONE,
|
|
276
|
+
"enable_oauth_google": self.oauth_provider == OAuthProvider.GOOGLE,
|
|
277
|
+
# Session Management
|
|
278
|
+
"enable_session_management": self.enable_session_management,
|
|
279
|
+
# Logfire
|
|
280
|
+
"enable_logfire": self.enable_logfire,
|
|
281
|
+
"logfire_fastapi": self.logfire_features.fastapi,
|
|
282
|
+
"logfire_database": self.logfire_features.database,
|
|
283
|
+
"logfire_redis": self.logfire_features.redis,
|
|
284
|
+
"logfire_celery": self.logfire_features.celery,
|
|
285
|
+
"logfire_httpx": self.logfire_features.httpx,
|
|
286
|
+
# Background tasks
|
|
287
|
+
"background_tasks": self.background_tasks.value,
|
|
288
|
+
"use_celery": self.background_tasks == BackgroundTaskType.CELERY,
|
|
289
|
+
"use_taskiq": self.background_tasks == BackgroundTaskType.TASKIQ,
|
|
290
|
+
"use_arq": self.background_tasks == BackgroundTaskType.ARQ,
|
|
291
|
+
# Integrations
|
|
292
|
+
"enable_redis": self.enable_redis,
|
|
293
|
+
"enable_caching": self.enable_caching,
|
|
294
|
+
"enable_rate_limiting": self.enable_rate_limiting,
|
|
295
|
+
"rate_limit_requests": self.rate_limit_requests,
|
|
296
|
+
"rate_limit_period": self.rate_limit_period,
|
|
297
|
+
"rate_limit_storage": self.rate_limit_storage.value,
|
|
298
|
+
"rate_limit_storage_memory": self.rate_limit_storage == RateLimitStorageType.MEMORY,
|
|
299
|
+
"rate_limit_storage_redis": self.rate_limit_storage == RateLimitStorageType.REDIS,
|
|
300
|
+
"enable_pagination": self.enable_pagination,
|
|
301
|
+
"enable_sentry": self.enable_sentry,
|
|
302
|
+
"enable_prometheus": self.enable_prometheus,
|
|
303
|
+
"enable_admin_panel": self.enable_admin_panel,
|
|
304
|
+
"admin_environments": self.admin_environments.value,
|
|
305
|
+
"admin_env_all": self.admin_environments == AdminEnvironmentType.ALL,
|
|
306
|
+
"admin_env_dev_only": self.admin_environments == AdminEnvironmentType.DEV_ONLY,
|
|
307
|
+
"admin_env_dev_staging": self.admin_environments == AdminEnvironmentType.DEV_STAGING,
|
|
308
|
+
"admin_env_disabled": self.admin_environments == AdminEnvironmentType.DISABLED,
|
|
309
|
+
"admin_require_auth": self.admin_require_auth,
|
|
310
|
+
"enable_websockets": self.enable_websockets,
|
|
311
|
+
"enable_file_storage": self.enable_file_storage,
|
|
312
|
+
"enable_ai_agent": self.enable_ai_agent,
|
|
313
|
+
"ai_framework": self.ai_framework.value,
|
|
314
|
+
"use_pydantic_ai": self.ai_framework == AIFrameworkType.PYDANTIC_AI,
|
|
315
|
+
"use_langchain": self.ai_framework == AIFrameworkType.LANGCHAIN,
|
|
316
|
+
"llm_provider": self.llm_provider.value,
|
|
317
|
+
"use_openai": self.llm_provider == LLMProviderType.OPENAI,
|
|
318
|
+
"use_anthropic": self.llm_provider == LLMProviderType.ANTHROPIC,
|
|
319
|
+
"use_openrouter": self.llm_provider == LLMProviderType.OPENROUTER,
|
|
320
|
+
"enable_conversation_persistence": self.enable_conversation_persistence,
|
|
321
|
+
"enable_webhooks": self.enable_webhooks,
|
|
322
|
+
"websocket_auth": self.websocket_auth.value,
|
|
323
|
+
"websocket_auth_jwt": self.websocket_auth == WebSocketAuthType.JWT,
|
|
324
|
+
"websocket_auth_api_key": self.websocket_auth == WebSocketAuthType.API_KEY,
|
|
325
|
+
"websocket_auth_none": self.websocket_auth == WebSocketAuthType.NONE,
|
|
326
|
+
"enable_cors": self.enable_cors,
|
|
327
|
+
"enable_orjson": self.enable_orjson,
|
|
328
|
+
# Frontend features
|
|
329
|
+
"enable_i18n": self.enable_i18n,
|
|
330
|
+
# Example CRUD
|
|
331
|
+
"include_example_crud": self.include_example_crud,
|
|
332
|
+
# Dev tools
|
|
333
|
+
"enable_pytest": self.enable_pytest,
|
|
334
|
+
"enable_precommit": self.enable_precommit,
|
|
335
|
+
"enable_makefile": self.enable_makefile,
|
|
336
|
+
"enable_docker": self.enable_docker,
|
|
337
|
+
# Reverse proxy
|
|
338
|
+
"reverse_proxy": self.reverse_proxy.value,
|
|
339
|
+
"include_traefik_service": self.reverse_proxy == ReverseProxyType.TRAEFIK_INCLUDED,
|
|
340
|
+
"include_traefik_labels": self.reverse_proxy
|
|
341
|
+
in (ReverseProxyType.TRAEFIK_INCLUDED, ReverseProxyType.TRAEFIK_EXTERNAL),
|
|
342
|
+
"ci_type": self.ci_type.value,
|
|
343
|
+
"use_github_actions": self.ci_type == CIType.GITHUB,
|
|
344
|
+
"use_gitlab_ci": self.ci_type == CIType.GITLAB,
|
|
345
|
+
"enable_kubernetes": self.enable_kubernetes,
|
|
346
|
+
"generate_env": self.generate_env,
|
|
347
|
+
# Python version
|
|
348
|
+
"python_version": self.python_version,
|
|
349
|
+
# Frontend
|
|
350
|
+
"frontend": self.frontend.value,
|
|
351
|
+
"use_frontend": self.frontend != FrontendType.NONE,
|
|
352
|
+
"use_nextjs": self.frontend == FrontendType.NEXTJS,
|
|
353
|
+
"frontend_port": self.frontend_port,
|
|
354
|
+
# Backend
|
|
355
|
+
"backend_port": self.backend_port,
|
|
356
|
+
}
|
fastapi_gen/generator.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Project generation logic."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from cookiecutter.main import cookiecutter
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
9
|
+
|
|
10
|
+
from .config import DatabaseType, FrontendType, ProjectConfig
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _get_database_setup_commands(database: DatabaseType) -> list[str]:
|
|
16
|
+
"""Get database-specific setup commands for post-generation messages.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
database: The database type selected by the user
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
List of command strings to display
|
|
23
|
+
"""
|
|
24
|
+
if database == DatabaseType.SQLITE:
|
|
25
|
+
return [
|
|
26
|
+
"# SQLite database will be created automatically at first run",
|
|
27
|
+
"make db-migrate # Create initial migration",
|
|
28
|
+
"make db-upgrade # Apply migrations",
|
|
29
|
+
]
|
|
30
|
+
elif database == DatabaseType.MONGODB:
|
|
31
|
+
return [
|
|
32
|
+
"make docker-mongo # Start MongoDB container",
|
|
33
|
+
"# Or configure MongoDB Atlas connection in .env",
|
|
34
|
+
]
|
|
35
|
+
else: # PostgreSQL
|
|
36
|
+
return [
|
|
37
|
+
"make docker-db # Start PostgreSQL container",
|
|
38
|
+
"make db-migrate # Create initial migration",
|
|
39
|
+
"make db-upgrade # Apply migrations",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _find_template_dir() -> Path:
|
|
44
|
+
"""Find the template directory.
|
|
45
|
+
|
|
46
|
+
Works both in development (template at project root) and when installed
|
|
47
|
+
(template bundled inside the package).
|
|
48
|
+
"""
|
|
49
|
+
# Development: template is at project root (sibling to fastapi_gen/)
|
|
50
|
+
dev_path = Path(__file__).parent.parent / "template"
|
|
51
|
+
if dev_path.exists() and (dev_path / "cookiecutter.json").exists():
|
|
52
|
+
return dev_path
|
|
53
|
+
|
|
54
|
+
# Installed: template is inside the package
|
|
55
|
+
installed_path = Path(__file__).parent / "template"
|
|
56
|
+
if installed_path.exists() and (installed_path / "cookiecutter.json").exists():
|
|
57
|
+
return installed_path
|
|
58
|
+
|
|
59
|
+
raise FileNotFoundError(
|
|
60
|
+
"Could not find cookiecutter template. "
|
|
61
|
+
"Expected at 'template/' (development) or 'fastapi_gen/template/' (installed)."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
TEMPLATE_DIR = _find_template_dir()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_template_path() -> str:
|
|
69
|
+
"""Get the path to the cookiecutter template."""
|
|
70
|
+
return str(TEMPLATE_DIR)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def generate_project(config: ProjectConfig, output_dir: Path | None = None) -> Path:
|
|
74
|
+
"""Generate a new FastAPI project from configuration.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
config: Project configuration
|
|
78
|
+
output_dir: Output directory (defaults to current directory)
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Path to the generated project
|
|
82
|
+
|
|
83
|
+
Raises:
|
|
84
|
+
ValueError: If target directory exists and is not empty
|
|
85
|
+
"""
|
|
86
|
+
if output_dir is None:
|
|
87
|
+
output_dir = Path.cwd()
|
|
88
|
+
|
|
89
|
+
# Check if target directory already exists and is not empty
|
|
90
|
+
target_dir = output_dir / config.project_slug
|
|
91
|
+
if target_dir.exists() and any(target_dir.iterdir()):
|
|
92
|
+
raise ValueError(f"Directory '{target_dir}' already exists and is not empty")
|
|
93
|
+
|
|
94
|
+
context = config.to_cookiecutter_context()
|
|
95
|
+
template_path = get_template_path()
|
|
96
|
+
|
|
97
|
+
with Progress(
|
|
98
|
+
SpinnerColumn(),
|
|
99
|
+
TextColumn("[progress.description]{task.description}"),
|
|
100
|
+
console=console,
|
|
101
|
+
) as progress:
|
|
102
|
+
progress.add_task(description="Generating project...", total=None)
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
# Generate project using cookiecutter
|
|
106
|
+
project_path = cookiecutter(
|
|
107
|
+
template_path,
|
|
108
|
+
extra_context=context,
|
|
109
|
+
output_dir=str(output_dir),
|
|
110
|
+
no_input=True,
|
|
111
|
+
)
|
|
112
|
+
except Exception:
|
|
113
|
+
# Cleanup partial files on failure
|
|
114
|
+
if target_dir.exists():
|
|
115
|
+
shutil.rmtree(target_dir)
|
|
116
|
+
raise
|
|
117
|
+
|
|
118
|
+
return Path(project_path)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def post_generation_tasks(project_path: Path, config: ProjectConfig) -> None:
|
|
122
|
+
"""Run post-generation tasks.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
project_path: Path to the generated project
|
|
126
|
+
config: Project configuration
|
|
127
|
+
"""
|
|
128
|
+
console.print()
|
|
129
|
+
console.print(f"[bold green]Project created at:[/] {project_path}")
|
|
130
|
+
console.print()
|
|
131
|
+
console.print("[bold cyan]Next steps:[/]")
|
|
132
|
+
console.print()
|
|
133
|
+
console.print(f" cd {project_path.name}")
|
|
134
|
+
|
|
135
|
+
step = 1
|
|
136
|
+
if config.frontend != FrontendType.NONE:
|
|
137
|
+
# Full-stack project
|
|
138
|
+
console.print()
|
|
139
|
+
if config.generate_env:
|
|
140
|
+
console.print(f"[bold]{step}. Environment:[/]")
|
|
141
|
+
console.print(" backend/.env and frontend/.env.local are pre-configured")
|
|
142
|
+
console.print(" # Review and update settings as needed")
|
|
143
|
+
else:
|
|
144
|
+
console.print(f"[bold]{step}. Configure environment:[/]")
|
|
145
|
+
console.print(" cd backend && cp .env.example .env")
|
|
146
|
+
console.print(" cd frontend && cp .env.example .env.local")
|
|
147
|
+
console.print(" # Edit with your settings (database, secrets, etc.)")
|
|
148
|
+
step += 1
|
|
149
|
+
console.print()
|
|
150
|
+
console.print(f"[bold]{step}. Install backend dependencies:[/]")
|
|
151
|
+
console.print(" make install")
|
|
152
|
+
step += 1
|
|
153
|
+
if config.database.value != "none":
|
|
154
|
+
console.print()
|
|
155
|
+
console.print(f"[bold]{step}. Database setup:[/]")
|
|
156
|
+
for cmd in _get_database_setup_commands(config.database):
|
|
157
|
+
console.print(f" {cmd}")
|
|
158
|
+
step += 1
|
|
159
|
+
console.print()
|
|
160
|
+
console.print(f"[bold]{step}. Run backend:[/]")
|
|
161
|
+
console.print(" make run")
|
|
162
|
+
step += 1
|
|
163
|
+
console.print()
|
|
164
|
+
console.print(f"[bold]{step}. Frontend setup (in new terminal):[/]")
|
|
165
|
+
console.print(" cd frontend")
|
|
166
|
+
console.print(" bun install")
|
|
167
|
+
console.print(" bun run dev")
|
|
168
|
+
else:
|
|
169
|
+
# Backend-only project
|
|
170
|
+
console.print()
|
|
171
|
+
if config.generate_env:
|
|
172
|
+
console.print(f"[bold]{step}. Environment:[/]")
|
|
173
|
+
console.print(" backend/.env is pre-configured for development")
|
|
174
|
+
console.print(" # Review and update settings as needed")
|
|
175
|
+
else:
|
|
176
|
+
console.print(f"[bold]{step}. Configure environment:[/]")
|
|
177
|
+
console.print(" cd backend && cp .env.example .env")
|
|
178
|
+
console.print(" # Edit backend/.env with your settings")
|
|
179
|
+
step += 1
|
|
180
|
+
console.print()
|
|
181
|
+
console.print(f"[bold]{step}. Install dependencies:[/]")
|
|
182
|
+
console.print(" make install")
|
|
183
|
+
step += 1
|
|
184
|
+
if config.database.value != "none":
|
|
185
|
+
console.print()
|
|
186
|
+
console.print(f"[bold]{step}. Database setup:[/]")
|
|
187
|
+
for cmd in _get_database_setup_commands(config.database):
|
|
188
|
+
console.print(f" {cmd}")
|
|
189
|
+
step += 1
|
|
190
|
+
console.print()
|
|
191
|
+
console.print(f"[bold]{step}. Run server:[/]")
|
|
192
|
+
console.print(" make run")
|
|
193
|
+
|
|
194
|
+
console.print()
|
|
195
|
+
|
|
196
|
+
if config.enable_logfire:
|
|
197
|
+
console.print("[dim]To enable Logfire, set LOGFIRE_TOKEN in backend/.env[/]")
|
|
198
|
+
console.print("[dim]Get your token at: https://logfire.pydantic.dev[/]")
|
|
199
|
+
console.print()
|
|
200
|
+
|
|
201
|
+
if config.frontend == FrontendType.NEXTJS:
|
|
202
|
+
console.print(f"[dim]Frontend runs on http://localhost:{config.frontend_port}[/]")
|
|
203
|
+
console.print(f"[dim]Backend API runs on http://localhost:{config.backend_port}[/]")
|
|
204
|
+
else:
|
|
205
|
+
console.print(f"[dim]API runs on http://localhost:{config.backend_port}[/]")
|
|
206
|
+
console.print(f"[dim]API docs: http://localhost:{config.backend_port}/docs[/]")
|
|
207
|
+
console.print()
|